bzoj 3668 //3668:[NOI2014]起床困难综合症

bzoj 3668 //3668:[NOI2014]起床困难综合症   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=3668

更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

方法一:用十进制模拟二进制

311ms / 1.53MB / 768B C++
//3668:[NOI2014]起床困难综合症
//在线测评地址https://www.luogu.org/problem/P2114
//题目出得不错,让人易懂,尤其喜欢题目对样例进行了详细说明。
//看了数据范围,那30分挺容易的。
//之后的分数就难拿了。
//看了数据范围,O(n)是省不了了,大胆猜测最终算法的时间复杂度O(nlogm)
//此文思路不错,摘抄如下
/*
又刷了一道水题QwQ

它给你n扇门,每扇门都有一个值和一个操作,这个操作为or、and、xor之间的某一个。你需要从m中任意选取一个数,使得这个数依次经过n扇门之后的值最大。

n是1e5的,m是1e9的,如果你直接暴力枚举每一个数,求最大值,复杂度显然是1e14的,爆炸了。简单换一个思路,我们考虑一个数大不大,可以在二进制的意义下考虑,想要得到最大值,我们应该尽可能让高位为1.因此我们枚举每一位,看它选0还是1可以让它经过n扇门之后尽量为1,累加一下答案就好了。复杂度为O(n*logn)。
*/
//样例通过,提交AC.2019-10-8
#include
#define maxn 100010
int pow[32],op[maxn],n,m,a[maxn],ans=0;
char cmd[5];
void init(){
    int i;
    pow[0]=1;
    for(i=1;i<=30;i++)pow[i]=2*pow[i-1];//第31位是符号位,整数0-31共占32位
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%s",cmd);
        if(cmd[0]=='A')op[i]=1;
        else if(cmd[0]=='O')op[i]=2;
        else if(cmd[0]=='X')op[i]=3;
        scanf("%d",&a[i]);
    }
}
int judge(int x,int now){
    int t,i;
    for(i=1;i<=n;i++){
        t=1&(a[i]>>x);
        if(op[i]==1)now&=t;
        else if(op[i]==2)now|=t;
        else if(op[i]==3)now^=t;
    }
    return now;
}
void solve(){
    int i;
    for(i=30;i>=0;i--)
        if(judge(i,0))ans+=pow[i];
        else if(pow[i]<=m&&judge(i,1))ans+=pow[i],m-=pow[i];//注意0&(0)=0,1&(0)=1 judge(i,0)==0,不代表judge(i,1)==1
    printf("%d\n",ans);
}
int main(){
    init();
    solve();
    return 0;
}
 

方法二:纯二进制做法

bzoj 3668

820 kb 300 ms C++/Edit 679 B

洛谷115ms / 688.00KB / 526B C++
//思路同方法一
//此文https://www.cnblogs.com/Repulser/p/9909096.html代码写得不错
//样例通过,提交0分,全WA.2019-10-8 19:48
/*
if(1&(bool_0>>i))ans|=(1<>i)ans|=(1< else if((1<>i))ans|=(1<>i)ans|=(1< */
//样例通过,提交0分,全WA.2019-10-8 19:49
//排查,发现在luogu中提交到P3668的题中去了,提交错位置了,昏了。
//样例通过,提交AC。2019-10-8 20:06
#include
char cmd[5];
int n,m,bool_0=0,bool_1=-1;
int main(){
    int i,j,a,ans=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%s%d",cmd,&a);
        if(cmd[0]=='A')bool_0&=a,bool_1&=a;
        else if(cmd[0]=='O')bool_0|=a,bool_1|=a;
        else if(cmd[0]=='X')bool_0^=a,bool_1^=a;
    }
    for(i=30;i>=0;i--)//第31位,符号位
        if(1&(bool_0>>i))ans|=(1<>i)ans|=(1<         else if((1<>i))ans|=(1<>i)ans|=(1<     printf("%d\n",ans);
    return 0;
}

方法三:bitset用法

139ms / 788.00KB / 479B C++
//基本思路同方法一
//代码参考此文https://www.cnblogs.com/fengxunling/p/9866998.html
//样例通过,提交AC.2019-10-8 20:42
#include
#include
using namespace std;
char cmd[5];
int n,m;
bitset<31> none,all;
int main(){
    int i,a,ans=0;
    none.reset();//每位设置为0
    all.set();//每位设置为1
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%s%d",cmd,&a);
        if(cmd[0]=='A')none&=a,all&=a;
        else if(cmd[0]=='O')none|=a,all|=a;
        else if(cmd[0]=='X')none^=a,all^=a;
    }
    for(i=30;i>=0;i--)
        if(none[i])ans|=(1<         else if((1<     printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(跟着大佬学算法)