Codeforces Round 960 (Div. 2)
题目链接:Codeforces Round 960 (Div. 2)
总结:Awa 2,Bwa 2,C一直wa。很难评价的一场。感觉D < C
A. Submission Bait
fag:博弈论
Description:给定\(n\)个数,初始有一个变量\(mx\),两个玩家。每一轮操作选一个大于等于\(mx\)的数\(a_i\),令\(a_i = 0, mx = a_i\)。不能操作的人输,问先手玩家是否能赢。
Solution:我们先考虑直接选最大值的情况,如果有奇数个最大值,那么先手赢。
- 考虑有偶数个最大值,怎么做?显然我们不能选最大值,考虑次大值有奇数个,那么先手赢。如果次大值也有偶数个,只能再往下考虑。
- 那么从最大次开始判断,只有有一个值有奇数个,那么先手赢,否则后手赢。
Competing: 第一发,只考虑了最大值的奇偶性;第二发,考虑了最大值的奇偶性和剩下所有数之和的奇偶性。
void solve(){
cin >> n;
vector<int> a(n + 1);
for (int i = 0; i < n; i ++){
int x;
cin >> x;
a[x] ++;
}
for (int i = n; i; i --){
if (a[i] & 1){
cout << "Yes\n";
return;
}
}
cout << "No\n";
}
B. Array Craft
fag:构造
Description: 给定一个\(n\), 一个\(x, y\)。其中\(x\)为最大前缀位置:就是令前缀和最大且下标最小的下标。\(y\)为最大位置:就是令后缀和最大且下标最大的下标。\(1 <= y < x <= n\)。构造一个长度为\(n\)的数组,元素只能为\(1\)或\(-1\),满足上述条件。
Solution:先考虑\(x\),我们令\(x\)之后的数为\(0\),考虑\(y\),我们令\(y\)之前的数为\(0\)。然后令\([y, x]\)之间的数为\(1\)。
- 但是元素只能是\(-1\)或\(1\),因此我们需要用\(1, -1 , 1, -1, ...\)构造出\(0\)。构造时\(x\)之后应该紧跟\(-1\),\(y\)之前应该紧跟\(-1\)。
Competing:令\([y, x]\)区间的数全为\(-1\),没考虑到这可能导致前缀和最大值为\(0\)。
void solve(){
int x, y;
cin >> n >> x >> y;
vector<int> a(n + 1, 1);
for (int i = 1; i < y; i ++){
a[i] = -1;
}
for (int i = x + 1; i <= n; i ++)
a[i] = -1;
for (int i = y; i >= 0; i -= 2){
a[i] = 1;
}
for (int i = x; i <= n; i += 2)
a[i] = 1;
for (int i = 1; i <= n; i ++)
cout << a[i] << " \n"[i == n];
}
C. Mad MAD Sum
fag: 思维?
Description:定义MAD为数组中至少出现两次的最大值。没有则为\(0\)。给定一个长度为\(n\)的数组\(a\)。
- \(MAD([1, 2, 1]) = 1, MAD([2, 2, 2, 3, 3] = 3), MAD([1, 2, 3, 4]) = 0\)。
- 初始时,\(sum = 0\),每回合\(sum += a_i\);\(b\)数组更新为当前\(a\)数组的MAD,然后将\(a\)数组更新为\(b\)数组。
2 3 1 1 2 2 3 4 4 5
0 0 0 1 2 2 3 3 4 4
0 0 0 0 0 2 2 3 3 4
0 0 0 0 0 0 2 3 3 4
1 3 2 1 1 2 3 3
0 0 0 1 1 2 3 3
0 0 0 0 1 1 1 3
Solution:多模拟几组样例可以发现MAD数组一定是连续递增的。
- 我们可以观察到数组有右移的特征。
- 但是当MAD数组中出现一个数字时,下一轮它就会消失。因为MAD需要它至少出现两次。
- 因此我们第一轮得到一个MAD数组,然后再模拟一轮去掉单个数字,之后的每一轮都是向右移动一次。
Competing:只跑了一次就像得到答案,好像也是可以,但是比较麻烦。多模拟样例,注意特征,总结规律
void solve(){
cin >> n;
vector<int> a(n), b(n);
int ans = 0;
map<int, int> mp;
int mx = 0;
for (int i = 0; i < n; i ++){
cin >> a[i];
ans += a[i];
mp[a[i]] ++;
if (mp[a[i]] >= 2 && a[i] > mx){
mx = a[i];
}
b[i] = mx;
}
mp.clear();
mx = 0;
for (int i = 0; i < n; i ++){
ans += b[i];
mp[b[i]] ++;
if (mp[b[i]] >= 2 && b[i] > mx)
mx = b[i];
a[i] = mx;
}
for (int i = 0; i < n; i ++)
ans += a[i] * (n - i);
cout << ans << endl;
}
D. Grid Puzzle
fag:思维
Description:有长度为\(n\)的数组,其中\(a_i\)表示第\(i\)行,从\([1, a_i]\)都是黑色,其余是白色。有\(n * n\)的棋盘。
- 每次操作可以将一行染白,或者选一个\(2 * 2\)的矩阵染白。
- 求将棋盘染白的最少操作次数。
Solution:显然当\(a_i\)很大时,我们会直接将一行染白。考虑何时使用操作二。
- 如果我们在这一行使用操作二,只会影响到下一行。
- 每一行我们最大执行一次操作二,否则不如使用操作一。
- 如果\(a_i <= 2\),显然我们应该使用操作二,因为可以影响下一行。
- 假设当前行被上一行影响了,如果前两个格子被染白,并且\(a_i <= 2\)那么不需要执行操作;如果\(a_i <= 4\),如果前两个格子被(上一行)染白,我们需要使用操作二染白后两个格子。如果后两个格子被(上一行)染白,那么我们染白前两个格子;如果\(a_i > 4\),我们使用操作一。
- 根据以上分析,注意到我们需要记录每一行被上一个影响的前两个格子还是后两个格子。
/*
4
2 4 4 2
3
*/
void solve(){
cin >> n;
vector<int> a(n + 1);
vector<int> st(n + 1);
cnt ++;
int ans = 0;
for (int i = 0; i < n; i ++){
cin >> a[i];
if (a[i] == 0){
continue;
}
if (a[i] <= 2){
if (st[i] == 1)
continue;
else{
ans ++;
st[i + 1] = 1;
}
}
else if (a[i] <= 4){
if (st[i] == 1){
ans ++;
st[i + 1] = 2;
}
else if (st[i] == 2){
ans ++;
st[i + 1] = 1;
}
else
ans ++;
}
else{
ans ++;
}
}
cout << ans << endl;
}