Codeforces Round 897 (Div. 2)
Codeforces Round 897 (Div. 2)
A. green_gold_dog, array and permutation
分析:
由题意:
\[c_i = a_i - b_i
\]
\(c_i\)种类最多就是\(n\)个数都不同。
若\(a_i\)不断变大,\(b_i\)不断变小,那么\(c_i\)会不断变大。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> pii;
typedef pair<pair<ll, ll>, ll> piii;
#define fi first
#define se second
using i128 = __int128;
int n, m;
int lowbit(int x)
{
return x & -x;
}
void solve()
{
scanf("%d", &n);
vector<pii> a(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i].fi);
a[i].se = i;
}
sort(a.begin() + 1, a.end());
vector<int> b(n + 1);
int cnt = n;
for (int i = 1; i <= n; i++)
{
b[a[i].se] = cnt--;
}
for (int i = 1; i <= n; i++)
{
printf("%d ", b[i]);
}
printf("\n");
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
B. XOR Palindromes
分析:
如何获得回文串:
- 对半分,通过操作使左右两侧一样。
- 全部变成1或0
注意,如果总字符数为奇数,那么每个左右两边一样后,我们还可以将中间的字符进行一次翻转操作。
使得左右两边一样,除了将两边不同的变成相同的,还可以将两边相同的同时翻转。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> pii;
typedef pair<pair<ll, ll>, ll> piii;
#define fi first
#define se second
using i128 = __int128;
int n, m;
int lowbit(int x)
{
return x & -x;
}
void solve()
{
scanf("%d", &n);
string s;
cin >> s;
int l = 0;
int r = s.size() - 1;
int cnt = 0;
while (l < r)
{
if (s[l] != s[r])
{
cnt++;
}
l++;
r--;
}
unordered_map<int, int> q;
for (int i = 0; i < n; i++)
{
int x = s[i] - '0';
q[x]++;
}
string ans;
for (int i = 0; i <= n; i++)
{
ans += '0';
}
for (int i = cnt; i <= n / 2; i++)
{
if (i == cnt)
{
ans[i] = '1';
}
else
{
int t = i - cnt;
ans[cnt + t * 2] = '1';
}
}
if (n & 1)
{
for (int i = n - 1; i >= 0; i--)
{
if (ans[i] == '1')
{
ans[i + 1] = '1';
}
}
}
ans[q[0]] = '1';
ans[q[1]] = '1';
cout << ans << endl;
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
C. Salyg1n and the MEX Game
分析:
直接贪心了,第一次添加\(MEX(S)\),之后删了啥加啥。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> pii;
typedef pair<pair<ll, ll>, ll> piii;
#define fi first
#define se second
using i128 = __int128;
int n, m;
int lowbit(int x)
{
return x & -x;
}
void solve()
{
scanf("%d", &n);
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
int cur = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] == cur)
{
cur++;
}
else
{
break;
}
}
while (true)
{
printf("%d\n", cur);
fflush(stdout);
scanf("%d", &cur);
if (cur == -1)
{
return;
}
}
}
int main()
{
int t = 1;
scanf("%d", &t);
while (t--)
{
solve();
}
return 0;
}
D - Cyclic Operations
分析:
如果\(k = 1\),那么,所有\(a_i = i\),否则就寄了。
如果\(k \neq 1\),那么,我们让\(i\)向\(a_i\)连边,若构成的基环树上的环中点数等于\(k\)就可以,否则就寄了。
注意:可能有多个基环树。如果后面构成的树连着连着连到了之前出现过的基环树上,那么同样合法。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> pii;
#define fi
#define se
void solve()
{
int n, k;
scanf("%d %d", &n, &k);
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
if (k == 1)
{
for (int i = 1; i <= n; i++)
{
if (a[i] != i)
{
puts("NO");
return;
}
}
puts("YES");
return;
}
vector<int> st(n + 1, -1);
for (int i = 1; i <= n; i++)
{
int cur = i;
while (st[cur] == -1)
{
st[cur] = i;
cur = a[cur];
}
// 连到之前树上直接ok
if (st[cur] == i)
{
int j = cur;
int len = 0;
do
{
len++;
j = a[j];
} while (j != cur);
if (len != k)
{
puts("NO");
return;
}
}
}
puts("YES");
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
E. Salyg1n and Array (hard version)
分析:
\(k\)最大只有\(50\),所以,如果\(n \% k == 0\),直接暴力遍历即可。
否则我们只需要处理最后一段,即\(n - (n \%k) \sim n\))$这一段。
由于\(n,k\)都是偶数,那么最后这段长度也一定会是偶数。
假设\(k = 6\),最后这一段长度为\(4\),我们这里就要用到题中查询一段,这一段就会翻转的性质。
假设此时最后\(8\)个数是\([1,2,3,4,5,6,7,8]\)。
我们的目标是让\(ans = ans \oplus 5 \oplus 6\oplus 7\oplus8\)。
我们先异或上[1…6]这段区域,此时序列变为\([6,5,4,3,2,1,7,8]\),然后我们在异或上最后\(k\)个数即\([4,3,2,1,7,8]\)。
不难发现,\([1,2,3,4]\)被异或了两次,所以得到了答案。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int,int> pii;
#define fi
#define se
void solve()
{
int n,k;
cin>>n>>k;
int idx = 1;
ll ans = 0;
while(idx + k - 1 <= n)
{
printf("? %d\n",idx);
fflush(stdout) or cout.flush();
int x;
cin>>x;
idx += k;
ans ^= x;
}
if(idx == n + 1)
{
printf("! %d\n",ans);
fflush(stdout) or cout.flush();
return;
}
int res = n - idx + 1;
int t = res / 2;
printf("? %d\n",n - t - k + 1);
fflush(stdout) or cout.flush();
int x;
cin>>x;
ans ^= x;
printf("? %d\n",n - k + 1);
fflush(stdout) or cout.flush();
cin>>x;
ans ^= x;
printf("! %d\n",ans);
fflush(stdout) or cout.flush();
}
int main()
{
int t = 1;
cin >> t;
while(t--)
{
solve();
}
return 0;
}