codeforce 刷题(三)
CodeForces 1325D Ehab the Xorcist
题解
重点在于怎么使用异或运算,首先
- \(u <= v\) 才可能有解,因为异或只会使和减小,毕竟两个数的二进制表示的相同位置上\(1 \bigoplus 1 = 0\)
- \(u\) 和 \(v\) 肯定同奇或者同偶才有解,因为异或后是奇数,说明这些数中的奇数个数也是奇数,它们的和肯定也是奇数,具体一点的说,考虑它们的二进制表示,\(u\) 是奇数代表着二进制末尾为1的数有奇数个,然后整数相加等于它们的二进制相加,得到的和用二进制表示的话,末尾肯定也是1,所以和是个奇数。偶数同理
然后分类讨论,
- \(u = v\),输出\(u\)
- \(u < v\),因为\(u\) 和 \(v\) 同奇偶性,故 \(v - u\) 必定是个偶数,可以将它们的差拆分成两个相等的数。令 \(v - u = 2 * t\),有 \(u + t + t = v\),\(u \bigoplus t \bigoplus t = u\),表明序列:\(u\),\(t\),\(t\) 可能是解。观察样例1会发现,序列也有可能仅由两个数构成就可以啦,那么在什么情况下,只会用到两个数?假如 \(u \bigoplus t = u + t\),那么就能将\(u\) 和 \(t\) 合并成一个数 $u \bigoplus t $
注意0,0的样例输出的是0;还有爆
int
int main()
{
long long u, v;
cin >> u >> v;
if (u > v || (u + v) & 1) {
puts("-1");
}
else if (v == u) {
if (!v) puts("0");
else cout << 1 << "\n" << u << endl;
}
else {
int t = (v - u) / 2;
if ((u ^ t) == u + t) {
cout << 2 << "\n" << u + t << " " << t << endl;
}
else {
cout << 3 << "\n" << u << " " << t << " " << t << endl;
}
}
return 0;
}
CodeForces 1321C Remove Adjacent
给一个字符串,每次操作能删除一个字符 当且仅当 它的相邻字符是字母表位置的前一个字符,比如:b
的前一个字符在字母表中是a
,求最大操作次数
题解
显然先删除在字母表中顺序靠后的字符最优,理解题意后,很自然的想法。
用
for
循环的话要正向来一遍,反向来一遍,比如样例:bbbabbb
int main()
{
int n;
string s;
cin >> n >> s;
int m = s.size();
char ms[200];
for (char a = 'z'; a > 'a'; a--) {
int t = 0;
char last = s[0];
// 正向
myfor(i, 0, m) {
if (s[i] == a) {
if ((i > 0) && (last - 'a' == a - 'a' - 1)) continue;
if ((i < m - 1) && (s[i + 1] - 'a' == a - 'a' - 1) continue;
}
last = ms[t++] = s[i];
}
m = t;
myfor(i, 0, t) s[i] = ms[i];
// 反向
t = 0;
last = s[m - 1];
for (int i = m - 1; i >= 0; --i) {
if (s[i] == a) {
if ((i > 0) && (s[i - 1] - 'a' == a - 'a' - 1)) continue;
if ((i < m - 1) && (last - 'a' == a - 'a' - 1)) continue;
}
last = ms[t++] = s[i];
}
m = t;
myfor(i, 0, t) s[i] = ms[i];
}
cout << n - m << endl;
return 0;
}