CoFun 1612 单词分组(容斥)

时间:2021-08-23 03:36:25

Description

Stan有N个不同的单词,这天,Stan新结交的两个朋友来他这里玩,Stan作为主人,他需要送给他们单词,但由于Stan不能偏心,所以Stan给每个单词一个权值v_i,他需要他这N个单词恰好分配给这两个朋友,这个地方的人很奇怪,他们用来定义自己的喜悦值的方式是把所有得到的单词的权值都位运算and起来的值,所以你需要使得两个朋友的喜悦值是相同的

好学的Stan不满足于求出一种方案,而是想要知道总共有多少种方案数,Stan觉得这个太简单了,所以请你来帮他解决吧。

Input Format

第一行包含一个整数N

第二行包含N个非负整数,表示每个单词的权值

Output Format

输出仅一行,即方案数

 #include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define ll long long
ll f[][][][][],ans=;
int n,a[],mx,bin[];
int b[][],m,num,fa[];
int read(){
char ch=getchar();int t=,f=;
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
void sbpianfen(){
for (int i=;i<=n;i++){
int now=i&,pre=now^;
if (i==){
f[now][a[i]][][][]=;
f[now][][a[i]][][]=;
continue;
}
for (int j=;j<=mx;j++) for (int k=;k<=mx;k++) for (int l=;l<=;l++) for (int z=;z<=;z++) f[now][j][k][l][z]=;
for (int j=;j<=mx;j++)
for (int k=;k<=mx;k++){
if (k==)
f[now][j&a[i]][k][][]+=f[pre][j][k][][];
f[now][j&a[i]][k][][]+=f[pre][j][k][][];
if (j==)
f[now][j][k&a[i]][][]+=f[pre][j][k][][];
f[now][j][k&a[i]][][]+=f[pre][j][k][][];
}
for (int j=;j<=mx;j++){
f[now][a[i]][j][][]+=f[pre][][j][][];
f[now][j][a[i]][][]+=f[pre][j][][][];
}
}
ans=;
for (int i=;i<=mx;i++)
ans+=f[n&][i][i][][];
printf("%lld\n",ans);
}
int find(int x){
if (fa[x]==x) return x;
else return (fa[x]=find(fa[x]));
}
void dfs(int dep,int delta){
if (dep==m){
ans+=(ll)delta*(((ll)<<num));
return;
}
dfs(dep+,delta);
int tnum=num;
int tmp[];
for (int j=;j<n;j++) tmp[j]=fa[j];
int T;
for (T=;!b[dep][T];T++);
int f=find(T);
for (int j=T+;j<n;j++)
if (b[dep][j]){
int xx=find(j);
if (xx!=f){
fa[xx]=f;
num--;
}
}
dfs(dep+,-delta);
for (int j=;j<n;j++)
fa[j]=tmp[j];
num=tnum;
}
void sxpianfen(){
m=;
for (int i=;i<;i++){
int t=<<i,cnt=;
for (int j=;j<n;j++)
if (a[j]&t) cnt++;
if (cnt==||cnt==n) continue;
for (int j=;j<n;j++)
if (!(a[j]&t)) b[m][j]=;
else b[m][j]=;
m++;
}
for (int i=;i<n;i++)
b[m][i]=,fa[i]=i;
m++;
ans=;
num=n;
dfs(,);
printf("%lld\n",ans);
}
int main(){
n=read();
for (int i=;i<n;i++) a[i]=read();
sxpianfen();
}