bzoj3668 [Noi2014]起床困难综合症——贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3668
一开始想着倒序推回去看看这一位能不能达到来着,因为这样好中途退出(以为不这样会T);
没想到正着的0和1可能出现一样的结果...
这是WA代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=1e5+5; int n,m,t[maxn],ans,cnt[60],op[maxn],c; char ch[5]; int cal(int x) { memset(cnt,0,sizeof cnt); int ret=0; while(x)cnt[++ret]=x%2,x/=2; return ret; } int main() { scanf("%d%d",&n,&m); int mx=0; for(int i=1;i<=n;i++) { scanf("%s%d",&ch,&t[i]); if(ch[0]=='A')op[i]=1;//& if(ch[0]=='O')op[i]=2;//| if(ch[0]=='X')op[i]=3;//^ mx=max(mx,t[i]); } int k=cal(mx); for(int i=k;i;i--) { // if(ans+(1<<(i-1))>m)continue; bool flag=0;int nw=1; for(int j=n;j;j--) { cal(t[j]); if(op[j]==1&&nw==1&&cnt[i]==0){flag=1;break;} if(op[j]==2&&nw==0&&cnt[i]==1){flag=1;break;} if(op[j]==3)nw^=cnt[i]; } if(!flag) { if(nw==0)ans+=(1<<(i-1)); else if(c+(1<<(i-1))<=m)c+=(1<<(i-1)),ans+=(1<<(i-1)); } } printf("%d",ans); return 0; }
而且 i 不是从 mx 的最高位开始而是从 m 的最高位开始的...
也不用中途退出什么的,因为位数没有那么大;
可以先用0得到一个 ans 作为底线,然后看看能不能通过某些位上放1让答案更大。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=1e5+5; int n,m,t[maxn],ans,cnt[60],op[maxn],c; char ch[5]; int cal(int x) { memset(cnt,0,sizeof cnt); int ret=0; while(x)cnt[++ret]=x%2,x/=2; return ret; } int main() { scanf("%d%d",&n,&m); int mx=0; for(int i=1;i<=n;i++) { scanf("%s%d",&ch,&t[i]); if(ch[0]=='A')op[i]=1,ans&=t[i];//& if(ch[0]=='O')op[i]=2,ans|=t[i];//| if(ch[0]=='X')op[i]=3,ans^=t[i];//^ }//得到输入0后的ans int k=cal(m);k--; for(int i=k;i>=0;i--) { int tmp=(1<<i); if(tmp>m||(ans&(1<<i)))continue; for(int j=1;j<=n;j++) { if(op[j]==1)tmp&=t[j]; if(op[j]==2)tmp|=t[j]; if(op[j]==3)tmp^=t[j]; } if(tmp&(1<<i))ans|=(1<<i),m-=(1<<i); } printf("%d",ans); return 0; }