zoukankan      html  css  js  c++  java
  • 【bzoj2728】[HNOI2012]与非

    先打出nand表
    0 nand 0=1
    1 nand 1=0
    0 nand 1=1
    1 nand 0=1
     
    容易发现(!a)=a nand a
    然后(a&b)=!(a nand b)
    然后(a|b)=!((!a)&(!b))
    然后(a^b)=(a|b)&(a nand b)
     
    所以通过nand我们可以实现任意一种位运算
    所以每一位我们想得到0/1都是可以的
    按道理[L,R]中符合位数要求的数都能得到
     
    然而我们发现这样一个显然的结论:
    如果A序列中每个数的第i位和第j位都相等,那么不论怎么nand,我们得到的数的第i位和第j位一定会相等。
    不妨设这种限制条件为(i,j)。
     
    于是我们统计[L,R]中符合这个限制条件的数即可。
     
    首先从高位找x的第一个1,进行决策。
    如果我们不选这个1,那么剩下的未决策位可以随便取,答案加上2^未决策位数。
    如果我们选这个1,那么从这个1开始接下来一段的0必须取0(取1的话一定是大于R的数),于是直接考虑下一个1的决策。
    再考虑限制条件。我们设xd[i]=符合(i,j)限制的最小j,那么决策第i位为1时,我们也会决策第xd[i]位必须为1。必须取0的决策同理。
    如果准备决策某一位,发现其已经被限制,则我们需要判断一下,如果已有限制与当前要给它的决策一致,则不用管了。如果希望决策它为1但它必须为0,那么这一位我们只能决策它为0,加上答案,后面的1都不用再枚举了。如果希望决策它为0但它必须为1,那么说明没办法决策出符合要求的数,直接break。
    这样得到的是[0,x-1]中符合要求的数,因为我们不选第一个1就可以决策到0,然而我们决策完最后一个1也决策不出x。
     
    答案就是query(r+1)-query(l)。
     
    (以上来自XZY大神犇空间。。。)
     
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
     
    typedef long long LL;
     
    LL k,n,l,r;
     
    LL a[1010<<2];
    int s[110],xd[110];
    int res;
     
    bool flag(true);
     
    bool check(int i,int j)
    {
        for (int m=1;m<=n;m++)
            if (((a[m]>>i) ^ (a[m]>>j)) & 1)
                return false;
        return true;
    }
     
    LL query(LL x)
    {
        LL ans=0;
        if (x>=(1LL<<k))
            return 1LL<<res;
        int u,v=res;
        for (int i=0;i<=64;i++)
            s[i]=2;
        for (int i=k-1;i>=0;i--)
        {
            u=xd[i];
            if ((x>>i) & 1)
            {
                if (s[u]==2)
                    s[u]=1,v--,ans+=(1LL<<v);
                else if (s[u]==0)
                {
                    ans+=(1LL<<v);
                    break;
                }
            }
            else
                if (s[u]==2)
                    s[u]=0,v--;
                else if (s[u]==1)
                    break;
        }
        return ans;
    }
     
    int main()
    {
        scanf("%lld%lld%lld%lld",&n,&k,&l,&r);
        for (int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for (int i=0;i<=k-1;i++)
        {
            int j;
            for (j=0;j<=i-1;j++)
                if (check(i,j))
                {
                    xd[i]=j;
                    break;
                }
            if (i==j)
                xd[i]=i,res++;
        }
        LL s1=query(r+1);
        LL s2=query(l);
        printf("%lld",s1-s2);
        return 0;
    }
    

      

  • 相关阅读:
    Python中的结构化数据分析利器-Pandas简介
    A great tutorial with Jupyter notebook for ML beginners
    快速修改Matlab默认启动路径(Windows/Mac)
    十大opengl教程
    vtk 基础概念
    OpenGL入门学习
    glut glew区别
    测试程序
    说说C语言运算符的“优先级”与“结合性”
    c++ ACM常用函数
  • 原文地址:https://www.cnblogs.com/yangjiyuan/p/5321092.html
Copyright © 2011-2022 走看看