CodeForces 1325D Ehab the Xorcist
题解
重点在于怎么使用异或运算,首先
- (u <= v) 才可能有解,因为异或只会使和减小,毕竟两个数的二进制表示的相同位置上(1 igoplus 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 igoplus t igoplus t = u),表明序列:(u),(t),(t) 可能是解。观察样例1会发现,序列也有可能仅由两个数构成就可以啦,那么在什么情况下,只会用到两个数?假如 (u igoplus t = u + t),那么就能将(u) 和 (t) 合并成一个数 $u igoplus 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 << "
" << u << endl;
}
else {
int t = (v - u) / 2;
if ((u ^ t) == u + t) {
cout << 2 << "
" << u + t << " " << t << endl;
}
else {
cout << 3 << "
" << 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;
}