题意: 给定
n
n
n个操作和数
m
m
m,问当初值在
[
1
,
m
]
[1,m]
[1,m]时,按照
n
n
n个操作的顺序操作后可以获得的最大值。
数据范围:
1
≤
n
≤
1
0
5
,
1
≤
m
≤
1
0
9
1\leq n\leq 10^5, 1\leq m\leq 10^9
1≤n≤105,1≤m≤109,操作只有或运算,与运算和异或运算三种。
题解:
位运算每位独立,故可以单独考虑每位。
- 由于二进制每位只有两种取值,故可以考虑每位初值为0和1的情况。那么对应的十进制初值只需要用两个数: a 0 = 0 a_0=0 a0=0和不小于 m m m的梅森数 a 1 a_1 a1即可,对应二进制位即全 0 0 0和全 1 1 1。
- 在对 a 0 a_0 a0和 a 1 a_1 a1进行 n n n组操作后,记操作后的数为 s 0 s_0 s0和 s 1 s_1 s1。
- 优先处理二进制高位,保证答案最大。同时在取可以为 1 1 1的位时,优先取由 a 0 a_0 a0转移过来的。当考虑 a 1 a_1 a1转移过来的位时,保证此时的位十进制大小加上之前的大小和不大于 m m m
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
int a0 = 0, a1 = -1;
for(int i = 1; i <= n; ++i) {
char op[10]; int x;
scanf("%s%d", op, &x);
if(*op == 'A') a0 &= x, a1 &= x;
else if(*op == 'X') a0 ^= x, a1 ^= x;
else a0 |= x, a1 |= x;
}
int sum = 0;
for(int i = 1 << 29; i >= 1; i >>= 1) {
if(a0 & i) sum |= i;
else if((a1 & i) && i <= m) sum |= i, m -= i;
}
printf("%d\n", sum);
return 0;
}