Codeforces D. Jzzhu and Numbers 【容斥+高维前缀和】

题目传送门
【考查点:容斥原理的理解,高维前缀和求解】
题意:给 n ( n <= 1 e 6 ) 个数,每个数都小于等于 1 e 6 , 求其中取任意个数&值为0的方案数?
题解:我们先求解&和不为零的情况。我们令 d [ x ] a i & x == x 的所有 a i 数目。对于每个 x d [ x ] 它们中任意取数&和都不为零。其方案数为 ( 2 f ( x ) 1 )
根据容斥原理所有&和不为0的方案数为

i = 1 1 e 6 ( 1 ) g ( x ) + 1 ( 2 f ( x ) 1 1 )

a n s = 2 n 1 i = 1 1 e 6 ( 1 ) g ( x ) + 1 ( 2 f ( x ) 1 1 )

由于 f ( 0 ) == n

a n s = i = 0 1 e 6 ( 1 ) g ( x ) ( 2 f ( x ) 1 1 )

然后求解f(x)过程就是一个求解高维前缀和过程。

ACcode

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD=1e9+7;
const int N=1<<20;
int d[N];
LL p[N];
int bt[25],n,x;
int main()
{
    for(int i=0;i<=20;i++)bt[i]=1<<i;
    p[0]=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        d[x]++;
        p[i]=p[i-1]<<1;
        if(p[i]>=MOD)
            p[i]-=MOD;
    }
       for(int j=0;j<=20;j++)
        for(int i=0;i<=1000000;i++)
        {
            if(i&bt[j])
                d[i^bt[j]]+=d[i];
        }
    LL ans=0,cur;
    for(int i=0;i<=1000000;i++)
    {
        if(d[i])
        {
            cur=p[d[i]]-1;
            if(__builtin_popcount(i)&1)
                ans=(ans+MOD+MOD-cur)%MOD;
            else
                ans=(ans+cur)%MOD;
        }
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/m0_37953323/article/details/79973285