Many Operations(位运算、递推)
题意
给定一个变量\(X\)和\(N\)个操作,每个操作用\((T_i, A_i)\)来表示。
- 如果\(T_i = 1\),则将\(X\)替换为\(X \& A_i\)
- 如果\(T_i = 2\),则将\(X\)替换为\(X | A_i\)
- 如果\(T_i = 3\),则将\(X\)替换为\(X xor A_i\)
将\(X\)初始化为\(C\),然后按照次序执行如下操作:
实施第\(1\)个操作,然后输出结果\(X\)
实施第\(1,2\)个操作,然后输出结果\(X\)
实施第\(1,2,3\)个操作,然后输出结果\(X\)
......
实施第\(1,2,\dots , N\)个操作,然后输出结果\(X\)
题目链接:https://atcoder.jp/contests/abc261/tasks/abc261_e
数据范围
\(1 \leq N \leq 2 \times 10^5\)
\(0 \leq C,A_i < 2^{30}\)
思路
这种题一般是进行递推。
一开始我想的是,递推\(A_1,A_2,\dots, A_i\),但是发现这个结论是错误的。
正确做法是对每一位分别进行考虑,并且分别假设每一位是\(0\)和\(1\),进行递推。
(有点难表达,直接看代码吧)
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 200010;
int n, c;
int op[N], x[N];
int f[35][2];
int main()
{
scanf("%d%d", &n, &c);
for(int i = 1; i <= n; i ++) scanf("%d%d", &op[i], &x[i]);
for(int i = 0; i < 30; i ++) f[i][1] = 1;
for(int i = 1; i <= n; i ++) {
for(int j = 0; j < 30; j ++) {
int t = x[i] >> j & 1;
if(op[i] == 1) {
f[j][0] &= t;
f[j][1] &= t;
}
else if(op[i] == 2) {
f[j][0] |= t;
f[j][1] |= t;
}
else {
f[j][0] ^= t;
f[j][1] ^= t;
}
}
int p = 0;
for(int j = 29; j >= 0; j --) {
int t = c >> j & 1;
p = p * 2 + f[j][t];
}
c = p;
printf("%d\n", c);
}
return 0;
}