题意:给你一个(N<=1e5)的序列,问有多少对(i,j)使得 a[i]&a[j] 为0。
题解:a[i] &a[j]==0表示a[j]在a[i]的补集内,即a[j] ⊂ \subset ⊂(U^a[i])。套套板子就可以了。
题意:给你(n<1e4)个长度为3的字符串,仅由‘a’~'x’组成。你要回答‘a’ ~‘x’组成的所有集合中。若其中一个字符串存在与集合相同的字符,那么这个字符串的贡献为1。问所有集合的贡献平方的异或和是多少?
容斥,初始化将每个字符串出现一次的字符+1,出现两次的字符-1,出现3次的字符+1。然后跑一遍板子就可以了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 24;
int F[(1<<24)+5];
char s[5];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=0;j<3;j++){
F[1<<(s[j]-'a')]++;
int ret=(1<<(s[j]-'a'));
for(int k=j+1;k<3;k++){
F[ret|(1<<(s[k]-'a'))]--;
}
}
F[(1<<(s[0]-'a'))|(1<<(s[1]-'a'))|(1<<(s[2]-'a'))]++;
}
for(int i=0;i<N;i++)for(int mask=0;mask<(1<<N);mask++){
if((mask>>i)&1)F[mask]+=F[mask^(1<<i)];
}
ll ans=0;
for(int i=0;i<(1<<N);i++){
ans ^= (ll)F[i]*F[i];
}
cout<<ans<<endl;
return 0;
}
题意,问一个数组的有多少个与值为0的子序列
反向思考。令F[mask]为 m a s k ⊂ i mask\subset i mask⊂i的情况,那么其的子集就可以表示与值至少为mask的集合。那么我们做个容斥就可以做完了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7;
const int maxn = 1e6+5;
const int N = 20;
int a[maxn];
int C[maxn];
int num[maxn];
int F[(1<<N)+5];
int n;
void init(){
C[0]=1;num[0]=0;
for(int i=1;i<=1000000;i++)C[i]=(ll)C[i-1]*2%mod,num[i]=num[i>>1]+(i&1);
}
int main(){
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),F[a[i]]++;
for(int i=0;i<N;i++)for(int mask=0;mask<(1<<N);mask++){
if((mask>>i)&1){
F[mask^(1<<i)]+=F[mask];
}
}
ll ans=0;
for(int i=0;i<(1<<N);i++){
if(F[i]){
ans = (ans+(C[F[i]]-1)*(num[i]&1?-1:1))%mod;
}
}
ans = (ans+mod)%mod;
cout<<ans<<endl;
return 0;
}