Thank you for participation and we hope you enjoy this round :)
A — Submission Bait
For Alice, what if choosing the maximum value doesn't work?
Consider parity.
Case $$$1$$$: When all values appear an even number of times, Alice will lose. This is because no matter which number Alice chooses, Bob can mimic Alice's move.
Case $$$2$$$: When at least one value appears an odd number of times, Alice will win. Alice only needs to choose the maximum value that appears an odd number of times, which will force Bob into Case $$$1$$$.
Time complexity: $$$O(n)$$$.
Sort the array $$$a$$$ in non-increasing order. We can observe that any state can be represented as a prefix of the array $$$a$$$. Consider dynamic programming: let $$$dp_i$$$ denote whether the first player is guaranteed to win when the state is $$$a_{1...i}$$$ ($$$dp_i=1$$$ indicates a guaranteed win for the first player). We have the following formula:
$$$dp_1=1$$$;
$$$dp_i= \sim (dp_{i-1}$$$ & $$$dp_{id_1-1}$$$ & $$$dp_{id_2-1} \ldots)$$$, where $$$id_j$$$ satisfies $$$a_{id_j} \neq a_{id_j+1}$$$ and $$$id_j < i$$$.
Time complexity: $$$O(n^2)$$$.
#include <bits/stdc++.h>
using namespace std;
#define m_p make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
typedef long long ll;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937 rnf(2106);
const int N = 55;
int n;
int q[N];
void solv()
{
cin >> n;
for (int i = 1; i <= n; ++i)
q[i] = 0;
for (int i = 1; i <= n; ++i)
{
int x;
cin >> x;
++q[x];
}
for (int i = 1; i <= n; ++i)
{
if (q[i] % 2 == 1)
{
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
int main()
{
#ifdef SOMETHING
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif // SOMETHING
ios_base::sync_with_stdio(false), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--)
{
solv();
}
return 0;
}
B — Array Craft
Starting from a trival construction.
Adjust it.
First, we consider making $$$presum_x > presum_j$$$ for all $$$x < i \le n$$$, and similarly for $$$y$$$. We can think of a trivial construction: $$$a[r, \ldots ,l]=[1, \ldots ,1], a[1, \ldots...,r-1]=[-1, \ldots, -1]$$$ and $$$a[l+1,\ldots,n]=[-1, \ldots, -1]$$$.
The construction doesn't works when $$$presum_x<0$$$, but we are close to the correct solution. Next, we will make a little adjustment: $$$a[r, \ldots, l]=[1,\ldots,1], a[1, \ldots...,r-1]=[\ldots,1, -1]$$$ and $$$a[l+1,\ldots,n]=[-1,1, \ldots]$$$.
It is not hard to see $$$presum_x \ge presum_j$$$ for all $$$x < i \le n$$$, and for $$$1 \le i \le y$$$, $$$\max(presum_i)-min(presum_i)\le 1$$$. Thus, we get $$$presum_x \ge 2+presum_{y-1} \ge 2+min(presum_i) \ge 1+max(presum_i)$$$. The same applies to the suffix sum as well. Therefore, this construction is valid.
Time complexity: $$$O(n)$$$.
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t>0){
t--;
int n,x,y;
cin >> n >> x >> y;
x--; y--;
vector<int> a(n,1);
int e;
e=-1;
for(int i=x+1;i<n;i++){
a[i]=e;
e*=-1;
}
e=-1;
for(int i=y-1;i>=0;i--){
a[i]=e;
e*=-1;
}
for(int i=0;i<n;i++){
if(i){cout << " ";}
cout << a[i];
}cout << "\n";
}
return 0;
}
C — Mad MAD Sum
After one operation, the array becomes non-decreasing.
Consider $$$a_1=a_2=\ldots=a_n$$$, the operation seems to have shifted the array right.
When does the "right shift" parttern happen?
Read hints first.
Let's consider only non-decreasing arrays. Observe a continuous segments $$$a[l...r]=x(l<r,x>0)$$$, after one operation, we get $$$a[l+1,min(r+1,n)]=x$$$ holds. We can conclude that if, for all non-zero contiguous segments in the array (except the last one), their lengths are all greater than $$$1$$$, then the array follows the "right shift" parttern. Let's say this kind of array "good".
The last problem is when will the array become "good". Let's assume we get the array $$$b$$$ after one operation on array $$$a$$$, we get $$$b_i<b_{i+1}<b_{i+2}$$$. We can infer that $$$b_i=a_i,b_{i+1}=a_{i+1}$$$ and there is at least $$$a_j=a_{i+1}(j \le i)$$$, which shows that $$$a$$$ is not non-decreasing. In other words, after two operations, we can always get a "good" array. Then the calculating is trival.
Time complexity: $$$O(n)$$$.
#include <bits/stdc++.h>
using namespace std;
#define m_p make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
typedef long long ll;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937 rnf(2106);
const int N = 200005;
int n;
int a[N];
bool c[N];
void doit()
{
for (int i = 1; i <= n; ++i)
c[i] = false;
int maxu = 0;
for (int i = 1; i <= n; ++i)
{
if (c[a[i]])
maxu = max(maxu, a[i]);
c[a[i]] = true;
a[i] = maxu;
}
}
void solv()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
ll ans = 0;
for (int i = 1; i <= n; ++i)
ans += a[i];
doit();
for (int i = 1; i <= n; ++i)
ans += a[i];
doit();
for (int i = 1; i <= n; ++i)
ans += (n - i + 1) * 1LL * a[i];
cout << ans << "\n";
}
int main()
{
#ifdef SOMETHING
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif // SOMETHING
ios_base::sync_with_stdio(false), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--)
{
solv();
}
return 0;
}
The title "Mad MAD Sum" is not only a pun on the words Mad and MAD (Maximum Appearing Duplicate), but also implies the solution to the problem :)
D Grid Puzzle
Obviously, when $$$a_i$$$ is large enough, we will definitely use operation $$$2$$$ on the $$$i$$$-th line. What is its specific value?
It is $$$5$$$(try to prove it). Now we can only consider $$$a_i \le 4$$$ cases.
From left to right, consider a greedy solution or a DP solution.
We observe that, in fact, only the $$$>$$$ to the left of $$$p$$$ and the $$$<$$$ to the right of $$$p$$$ change the direction of the pinball placed at position $$$p$$$ initially.
For convenience, let's assume $$$s_p$$$ is $$$>$$$, $$$k=min(countright(1,p),countleft(p+1,n))$$$, and the pinball leaves from the left boundary(for other situations, we can handle them in a similar way).
We can obtain $$$right[1,\ldots,k]$$$ and $$$left[1,\ldots,k]$$$ through prefix sum + binary search, where $$$right$$$ represents the indices of $$$>$$$ to the left of $$$p$$$ (in decreasing order), and $$$left$$$ represents the indices of $$$<$$$ to the right of $$$p$$$ (in increasing order).
We use $$$right$$$ and $$$left$$$ to describe the trace of the pinball:
The first segment: the pinball moves from $$$right_1$$$ to $$$left_1$$$;
The second segment: the pinball moves from $$$left_1$$$ to $$$right_2$$$;
The third segment: the pinball moves from $$$right_2$$$ to $$$left_3$$$;
$$$\ldots$$$
The $$$2k$$$-th segment: the pinball moves from $$$left_k$$$ to the left boundary.
It is not difficult to observe that we can use prefix sum to store the sum of indices, and then quickly calculate the time when the pinball moves.
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
#define MODD 998244353
long long int bigmod(long long int a,long long int b){
long long int ans=1,powa=a;
while(b>0){
if(b%2==1){
ans*=powa;
ans%=MOD;
}
powa=powa*powa;
powa%=MOD;
b/=2;
}
return ans;
}
void func(){
int n;
cin >> n;
int arr[n];
for(int i=0;i<n;i++){
cin >> arr[i];
}
bool b1=0,b2=0;
int ans=0;
for(int i=0;i<n;i++){
if((!b1)&&(!b2)){
if(arr[i]==0) continue;
ans++;
if(arr[i]<=2) b1=1;
}
else if(b1){
b1=0;
if(arr[i]<=2) continue;
ans++;
if(arr[i]<=4) b2=1;
}
else{
b2=0;
if(arr[i]==0) continue;
ans++;
if(arr[i]<=4) b1=1;
}
}
cout << ans << '\n';
return;
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int t;
cin >> t;
while(t--){
func();
}
}
//i added the bigmod func to my code cause yes
#include <bits/stdc++.h>
using namespace std;
#define m_p make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
typedef long long ll;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937 rnf(2106);
const int N = 200005;
int n;
int a[N];
int dp[N];
void minh(int& x, int y)
{
x = min(x, y);
}
void solv()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
int minu[2] = {N, N};
for (int i = 1; i <= n; ++i)
{
dp[i] = dp[i - 1] + 1;
if (a[i] == 0)
minh(dp[i], dp[i - 1]);
if (a[i] <= 2)
minh(dp[i], i + minu[1 - i % 2]);
if (a[i] <= 2)
minh(minu[i % 2], dp[i - 1] - i);
else if (a[i] > 4)
minu[0] = minu[1] = N;
}
cout << dp[n] << "\n";
}
int main()
{
#ifdef SOMETHING
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif // SOMETHING
ios_base::sync_with_stdio(false), cin.tie(0);
int tt = 1;
cin >> tt;
while (tt--)
{
solv();
}
return 0;
}
E Catch the Mole
In fact, you don't need to hire the same Pokemon more than once.
Consider graph building.
How to reduce the number of edges in the graph?
```
```
F Polygonal Segments
```
```