bzoj3668 [Noi2014]起床困难综合症——贪心

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3668

一开始想着倒序推回去看看这一位能不能达到来着,因为这样好中途退出(以为不这样会T);

没想到正着的0和1可能出现一样的结果...

这是WA代码:

#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;
}

 

posted @ 2018-06-11 15:17  Zinn  阅读(181)  评论(0编辑  收藏  举报