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

  

posted @ 2016-03-25 21:00  Yangjiyuan  阅读(370)  评论(0编辑  收藏  举报