zoukankan      html  css  js  c++  java
  • BZOJ2728 HNOI2012与非(并查集+数位dp)

      容易发现x nand x=not x。并且使用这个性质有x and y=not(x nand y)=(x nand y)nand(x nand y)。也就是说nand运算可以作为not和and运算使用。并且显然not和and运算可以表示nand运算,那么两者等价。事实上这就可以表示所有位运算了。

      那么考虑位运算有什么事干不了。注意到如果每个数的第i位都和第j位相同, 那么无论怎么操作这两位都是相同的。大胆猜想这也是充分的,即除了这件事其他都能干。

      这样位就被分成了很多类,每一类的取值要求相同。类似数位dp搞一发考虑第一个未达限制的是哪一位就行了。

      各种细节,调到吐血,拿过7种分数,连过了都不知道是不是数据水了,没救。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 1010
    #define K 60
    #define ll long long
    ll read()
    {
        ll x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,k,d[K][K],fa[K];
    bool flag[K];
    ll l,r,num[K];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    ll calc(ll n)
    {
        ll s=0,m=0,cnt=0;
        for (int i=0;i<k;i++) if (find(i)==i) cnt++;
        memset(flag,0,sizeof(flag));
        for (int i=k-1;~i;i--)
        {
            if (find(i)==i) cnt--;
            if ((n&(1ll<<i))&&!flag[find(i)]) 
            {
                s+=1ll<<cnt;
                flag[find(i)]=1;
                if ((m|=num[find(i)])>n) break;
            }
        }
        for (int i=0;i<k;i++)
            for (int j=0;j<k;j++)
            if (find(i)==find(j)&&((n&(1ll<<i))>0)!=((n&(1ll<<j))>0)) return s;
        return s+1;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2728.in","r",stdin);
        freopen("bzoj2728.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),k=read(),l=read(),r=read();
        if (l>=(1ll<<k)) {cout<<0;return 0;}
        r=min(r,(1ll<<k)-1);
        for (int i=0;i<k;i++)
            for (int j=0;j<k;j++)
            d[i][j]=1;
        for (int i=1;i<=n;i++)
        {
            ll x=read();
            for (int p=0;p<k;p++)
                for (int q=0;q<k;q++)
                if (((x&(1ll<<p))>0)!=((x&(1ll<<q))>0)) d[p][q]=0;
        }
        for (int i=0;i<k;i++) fa[i]=i;
        for (int i=0;i<k;i++)
            for (int j=0;j<k;j++)
            if (d[i][j]) fa[find(i)]=find(j);
        for (int i=0;i<k;i++)
        num[find(i)]|=1ll<<i;
        cout<<calc(r)-(l?calc(l-1):0);
        return 0;
    }
  • 相关阅读:
    __dict__
    谷歌浏览器如何清除当前页面的缓存
    博客园插入超链接时如何取消下划线
    杂七杂八
    博客园首页如何添加 Live 2D 模型
    访问 IIS 元数据库失败 的解决方法 .
    VS 关于无法打开项目文件,此安装不支持该项目类型的问题
    汉字转为unicode
    Windchill 预览效果偏向左边
    MD04
  • 原文地址:https://www.cnblogs.com/Gloid/p/9600287.html
Copyright © 2011-2022 走看看