51nod 1407

版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/82222269

p a ( i ) 表示 i 的最低 a 位构成的数。
h a ( i ) 表示 i 的最高 a 为构成的数

f a ( i ) 表示在给出的数列 A 中,满足:
p a ( i ) p a ( A j ) = p a ( i )
h 20 a ( i ) = h 20 a ( A j )
j 的个数。

那么有转移方程:
i 的第 a 位为 1 时: f a ( i ) = f a 1 ( i )
i 的第 a 位为 0 时: f a ( i ) = f a 1 ( i ) + f a 1 ( i + 2 a 1 )

f 20 ( i ) 即为结果,时间复杂度 O ( n 2 n )

c ( i ) 表示 i 二进制中 1 的数量,由容斥可得:
a n s = i = 0 2 20 1 ( 1 ) c ( i ) ( 2 f 20 ( i ) 1 )

预处理一下幂,dp出来之后搞一搞就完事了。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
using namespace std;
//Container--
//
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const ll md=1e9+7;const int up=1e6,sup=(1<<20)-1;int ar[up+10],dp[21][sup+10],ze[sup+10];ll _2[up+10];
void _init(){
    int i,j,k,d,t;for(ze[0]=0,i=1;i<=sup;++i)ze[i]=ze[i^(i&-i)]+1;
    for(_2[0]=1,i=1;i<=up;++i)_2[i]=_2[i-1]*2%md;
};
bool cl(){
    int i,j,k,d,t,n;if(scanf("%d",&n)==-1)return 0;for(i=1;i<=n;scanf("%d",&ar[i++]));
    for(clr(dp[0]),i=1;i<=n;++i)dp[0][ar[i]]++;
    for(i=1;i<=20;++i)for(j=0;j<=sup;++j){
        if(j&(1<<(i-1)))dp[i][j]=dp[i-1][j];
        else
            dp[i][j]=dp[i-1][j]+dp[i-1][j^(1<<(i-1))];
    }
    ll rs=_2[n]-1;for(i=1;i<=sup;++i){
        if(ze[i]&1)rs=(md-_2[dp[20][i]]+1+rs)%md;
        else
            rs=(rs+_2[dp[20][i]]-1+md)%md;
    }
    printf("%lld\n",rs);
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    _init();while(cl());
    return 0;
};

猜你喜欢

转载自blog.csdn.net/u012345506/article/details/82222269
今日推荐