Codeforces - Jzzhu and Numbers

青煙繞指柔!發表於2021-01-03

題目連結:Codeforces - Jzzhu and Numbers


考慮反向列舉每個與運算不為0的集合個數,最後做差。
然後我們可以列舉每個最後與起來的答案,我們就可以利用容斥來做。先求出每個集合的超集個數,最後利用二進位制中1的個數來容斥。
當只有一個1的時候減去這個答案,2個1的時候,由於計算了2次所以加上,然後3個1減去依次類推。


AC程式碼:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+10,mod=1e9+7;
int n,a[N],dp[N],up,pw[N],res,cnt[N];
inline void add(int &x,int y){x+=y; if(x>=mod) x-=mod;}
signed main(){
	cin>>n; pw[0]=1; up=(1<<20)-1;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pw[i]=pw[i-1]*2%mod,dp[a[i]]++;
	for(int i=0;i<20;i++) for(int j=up;j>=0;j--) if(j>>i&1) add(dp[j^(1<<i)],dp[j]);
	res=pw[n]-1;
	for(int i=1;i<=up;i++){
		cnt[i]=cnt[i>>1]+(i&1);
		if(cnt[i]&1) res=(res-(pw[dp[i]]-1)+mod)%mod;
		else res=(res+(pw[dp[i]]-1)+mod)%mod;
	}
	cout<<res;
	return 0;
}

相關文章