题意
给定n个位运算操作,和每次运算的数,在[0,m]范围内找一个数使得最后操作出来的数最大。
2≤n≤105 ,2≤m≤230
题解
这道题当时是我做的,最初可以想到暴力枚举,可是ACM又不看部分分,过了一会突然想到位运算:顾名思义,就是一位一位计算,在二进制下每一位的计算互不影响。
所以就想到预处理出每一位我们取0或1时在这一位最后得到的数,然后跑一遍贪心就好,当取0这一位可以得到1肯定是最好的(空手套白狼),取1可以得到也是极好的(花一分钱买一分货,不过要看自己是否有这个本钱),最后就是不管取什么都得不到1(那么就不要浪费钱啊,后面还要用),这就是贪心步骤。我做的题好简单,而且我好像就只做了这个,还错了一堆小东西
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m;
int yuan[35];
int num[maxn][35];
int f[35][2];
int opt[maxn];
int ans;
template <class T>
void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void nice(int x,int j){
for(int i=0;i<=30;i++,x>>=1)num[j][i]=x&1;
}
void get(int j,int xx){
int x=xx;
for(int i=1;i<=n;i++)
if(opt[i]==0) x&=num[i][j];
else if(opt[i]==1) x|=num[i][j];
else x^=num[i][j];
f[j][xx]=x;
}
void dfs(int s,bool lim){
if(s<0) return ;
if(f[s][0]==1) ans+=1<<s,dfs(s-1,lim&&yuan[s]==0);
else if(f[s][1]==1&&(!lim||yuan[s]==1)) ans+=1<<s,dfs(s-1,lim&&yuan[s]==1);
else dfs(s-1,lim&&yuan[s]==0);
}
int main()
{
read(n);read(m);
for(int i=1;i<=n;i++){
char s[5];scanf("%s",s);
if(s[0]=='A') opt[i]=0;
else if(s[0]=='O') opt[i]=1;
else opt[i]=2;
int x;
scanf("%d",&x);
nice(x,i);
}
// for(int i=1;i<=n;i++,putchar(10))
// for(int j=5;j>=0;j--)
// printf("%d",num[i][j]);
for(int i=0;i<=30;i++) get(i,0),get(i,1);
for(int i=0;i<=30;i++,m>>=1) yuan[i]=m&1;
// for(int i=0;i<=5;i++)
// printf("%d %d
",f[i][0],f[i][1]);
dfs(30,true);
printf("%d",ans);
}
不过他们就用了两个数,全0和全1就预处理出来了,我佛了,想一想自己慢了好多