CodeForces 449D(容斥,DP

题目:给出N<=10^6)个数,每个数<=10^6. 从中选出至少1个数,易知有2^N-1种不同方案。那么在这些方案中,有多少种满足选出的所有数AND起来为0呢?

我是不会做的,找了一个题解然而看了好久看不懂,后来看了下官方题解发现我看得那个有个地方写错了。。。。

官方题解如下:

Firstly, we can use inclusion-exclusion principle in this problem. Let f(x) be the count of number i where Ai&x = x. Let g(x) be the number of 1 in the binary respresentation of x. Then the answer equals to .

Now the task is to calculate f(x) for every integer x between 0 and 220. Let fk(x) be the count of number i where Y0&X0 = X0 and X1 = Y1 (they are defined below).

We divide x and Ai into two parts, the first k binary bits and the other 20 - k binary bits. Let X0 be the first part of x and X1 be the second part of x. Let Y0 be the first part of Ai and Y1 be the second part of Ai.

We can calculate fk(x) in O(1):

The problem can be solved in O(n * 2n) now (n = 20 in this problem).

做的时候作死把pow函数里的乘数写成了int。。。。总是犯这种错误。。。我发誓以后不用int做数学题了。。。。然后,对于这个dp的思路究竟是咋想出来的还是没有啥头绪,估计下次碰到这种提还是不会吧。。。每次都能看懂题解然后下次又不会了啊。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<functional>
#include<queue>
using namespace std;
typedef long long ll;
const int maxv=1e5+30;
const ll mod=1000000007;
int N;
int a[1<<20];
int dp[22][1<<20];
int fpow(int x,ll p){
    int ans=1;
    ll xx=x;
    while(p>0){
        if(p&1)
        ans=(xx*ans)%mod;
        xx=(xx*xx)%mod;
        p>>=1;
    }
    return ans;
}
void add(int &a,int b){
    a=((a+b)%mod+mod)%mod;
}
int main(){
    ///freopen("in","r",stdin);
    cin>>N;
    for(int i=0;i<N;i++) scanf("%d",&a[i]);
    sort(a,a+N);
    for(int i=0;i<N;i++){
        if(a[i]&1) add(dp[0][a[i]],1),add(dp[0][a[i]-1],1);
        else add(dp[0][a[i]],1);
    }
    for(int i=1;i<20;i++){
        for(int j=1;j<(1<<20);j++){
            if(j&(1<<i)) add(dp[i][j],dp[i-1][j]);
            else add(dp[i][j],dp[i-1][j]),add(dp[i][j],dp[i-1][j+(1<<i)]);
        }
    }
    int ans=fpow(2,N)-1;
        for(int j=1;j<(1<<20);j++){
            int bb=__builtin_popcount(j);
            if(bb%2) add(ans,-fpow(2,dp[19][j])+1);
            else add(ans,fpow(2,dp[19][j])-1);
        }
    cout<<ans<<endl;
    return 0;
}
View Code

 

posted @ 2015-05-22 22:35  PlusSeven  阅读(230)  评论(0编辑  收藏  举报