BZOJ_3668_起床困难综合症

About Problem

  • The web : http://www.lydsy.com/JudgeOnline/problem.php?id=3668
  • The tab : 二进制,NOI

Solve

题目的意思就是给你一些操作C[1] - C[N],每个操作只有可能是AND(&), OR(|), XOR(^)中的一个。
然后给你一个数M。
设f(x)为 x 经过操作 C[1] - C[N] 后的得到的答案。
要求:


Score 50%

其实这个就很简单的,枚举每一个M,然后去跑N个步骤,然后找出最优解就可以。
复杂度O(M * N)

Code:

#include 
#include 

#ifdef _WIN32
#define lld I64d
#endif

const int Maxn = int(1e5) + 10;
int n, m, t[Maxn], com[Maxn];

int ans = 0;
void force1()
{
    for(int i = 0; i <= m; ++i)
    {
        int tmp = i;
        for(int j = 1; j <= n; ++j)
            if(com[j] == 1) tmp = tmp & t[j];
            else if(com[j] == 2) tmp = tmp | t[j];
            else if(com[j] == 3) tmp = tmp xor t[j];
        if(tmp > ans) ans = tmp;
    }
    printf("%d\n", ans);
    return;
}

int main()
{
    freopen("sleep.in", "r", stdin);
    freopen("sleep.out", "w", stdout);
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
        char s[5];
        scanf("%s %d", s, &t[i]);
        if(s[0] == 'A') com[i] = 1;
        else if(s[0] == 'O') com[i] = 2;
        else if(s[0] == 'X') com[i] = 3;
    }
    if(m <= 1000) force1();
    return 0;
}

Score 100%

既然M高达1e9,那么很明显不能枚举M了。
那我们换个思路,既然这里都是二进制计算,那么这些二进制计算有一个非常显著的特点,就是它的每一位都是相对独立的。
举个例子来说:

6 = 1 1 0
5 = 1 0 1
6 ^ 5 = 0 1 1
当你在计算从左往右数第2位时, 第一位和第三位均不会影响第二位的运算结果。

我们假设最后的答案是从 K 经过N步后得到的 f(K)。
那么我们是不是可以枚举 K 的每一个二进制位,然后看 K 的第 i 个二进制位为1更优 还是为0更优。
最后得到每一个二进制位的最有值,在贪心选取,看看得到的K会不会超过M。
再求出f(K)就OK了。
由于答案在1e9内,所以不会超过32位。
每位可以进行N次操作,所以复杂度为O(32 * N)

Code:

#include 
#include 

const int Maxn = (int)1e5 + 10;
int num[Maxn][40], t[Maxn], ans[40];
int N = 0;

int main()
{
    freopen("sleep.in", "r", stdin);
    freopen("sleep.out", "w", stdout);
    
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
        char s[5];
        scanf("%s %d", s, &t[i]);
        if(s[0] == 'A') num[i][0] = 1;
        else if(s[0] == 'O') num[i][0] = 2;
        else if(s[0] == 'X') num[i][0] = 3;
        int tmp = t[i], l = 0;
        while(tmp)
        {
            num[i][++l] = tmp % 2;
            tmp /= 2;
        }
    }
    for(int i = 31; i; --i)
    {
        int z = 0, o = 1;
        for(int j = 1; j <= n; ++j)
        {
            if(num[j][0] == 1) z &= num[j][i], o &= num[j][i];
            else if(num[j][0] == 2) z |= num[j][i], o |= num[j][i];
            else if(num[j][0] == 3) z = z xor num[j][i], o = o xor num[j][i];
        }
        if(o > z) ans[i] = 1;
        else ans[i] = 0;
    }
    for(int i = 31; i; --i)
        if(N + (ans[i] << (i-1)) <= m) N += (ans[i] << (i - 1));
    for(int i = 1; i <= n; ++i)
    {
        if(num[i][0] == 1) N &= t[i];
        else if(num[i][0] == 2) N |= t[i];
        else if(num[i][0] == 3) N ^= t[i];
    }
    printf("%d\n", N);
    return 0;
}


你可能感兴趣的:(BZOJ_3668_起床困难综合症)