1. 程式人生 > >貪心+位運算 NOI2014 起床困難綜合徵

貪心+位運算 NOI2014 起床困難綜合徵

題意:
你可以任意選擇一個 0 m 0-m 的數,有 n n 次操作,有n次操作,對於每次操作有三種情況:分別為&一個數,|一個數,和^一個數,求n次操作後最大能得到多少。

題解:
直接做並不好做,暴力列舉選哪個數的話很難進一步優化了。
這道題我們像很多位運算有關題目一樣按位考慮,因為每一個二進位制位之間互不影響。我們把數拆成二進位制數,從高位到低位考慮,我們列舉答案的每一位,因為越靠前的位為 1 1 答案越大。首先對於當前的情況,如果此時列舉到的這位為 1

1 的話,答案已經超過 m m ,即ans+(1<<i)>m時,就continue掉,否則將這位為 1 1 和這位為 0
0
所得到的答案通過 n n 次操作,看得到的答案哪個更大,來決定這一位填 1 1 還是填 0 0

#include<bits/stdc++.h>
using namespace std;
int n,m,opt[1001000],t[1001000],ans;
char s[10000];
int calc(int x)
{
    for(int i=1;i<=n;++i)
    {
        if(opt[i]==1)
            x&=t[i];
        else if(opt[i]==2)
            x|=t[i];
        else
            x^=t[i];
    }
    return x;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i)
    {
        scanf("%s%d",s+1,&t[i]);
        if(s[1]=='A')
            opt[i]=1;
        else if(s[1]=='O')
            opt[i]=2;
        else
            opt[i]=3;
    }	
    for(int i=31;i>=0;--i)
    {
        if(ans+(1<<i)>m)
            continue;
        else if(calc(ans+(1<<i))>calc(ans))
            ans+=(1<<i);
    }
    cout<<calc(ans);
    return 0;
}