您的位置:首页 > 运维架构

[容斥] Topcoder SRM div1-3 12004. SetAndSet

2017-10-31 17:19 363 查看
把所有数取反,转换成分成两个集合,集合或值相同。

容斥一下

每次枚举哪些位不满足条件,用并查集维护一下要在同一个集合的联通块就好了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

class SetAndSet{
public:
typedef long long ll;
vector<int> b[25];
int n,f[55],a[25],vis[55];
ll ans;

int Gfat(int x){
return f[x]==x?x:f[x]=Gfat(f[x]);
}

void dfs(int x,int y){
if(x>=20){
int cnt=0;
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=n;i++){
if(!vis[Gfat(i)]) cnt++,vis[Gfat(i)]=1;
}
if(y&1) ans-=(1LL<<cnt)-2; else ans+=(1LL<<cnt)-2;
return ;
}
dfs(x+1,y);
if(b[x].size()<1) return ;
int curf[55];
memcpy(curf,f,sizeof(curf));
//      for(int i=1;i<=n;i++) curf[i]=f[i];
int nf=Gfat(b[x][0]);
for(int j=1;j<b[x].size();j++)
f[Gfat(b[x][j])]=nf;
dfs(x+1,y+1);
memcpy(f,curf,sizeof(f));
//      for(int i=1;i<=n;i++) f[i]=curf[i];
}

ll countandset(vector<int> A){
n=A.size(); ans=0;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=0;i<n;i++)
for(int j=0;j<20;j++)
if(~A[i]>>j&1) b[j].push_back(i+1);
dfs(0,0);
for(int i=0;i<20;i++) b[i].clear();
return ans;
}
};

inline void run_(int test_){
vector<int> a; SetAndSet A;
if(test_==0){ a.push_back(1); a.push_back(2); cout<<A.countandset(a)<<endl; }
if(test_==1){ a.push_back(1); a.push_back(2); a.push_back(3); a.push_back(4); cout<<A.countandset(a)<<endl;}
if(test_==2){ for(int i=1;i<=5;i++) a.push_back(i); cout<<A.countandset(a)<<endl; }
if(test_==3){ for(int i=1;i<=3;i++) a.push_back(6); cout<<A.countandset(a)<<endl; }
if(test_==4){ a.push_back(13); a.push_back(10); a.push_back(4); a.push_back(15); a.push_back(4); a.push_back(8); a.push_back(4); a.push_back(2); a.push_back(4); a.push_back(14); a.push_back(0); cout<<A.countandset(a)<<endl;}
if(test_==5){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int n;scanf("%d",&n);
for(int i=1,x;i<=n;i++)
scanf("%d",&x),a.push_back(x);
cout<<A.countandset(a)<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: