Sleep Buddies (二进制状态压缩)
Sleep Buddies
算法:状态压缩, 把每一个集合都压缩成一个数字。
使用方法:把每个状态都进行1<<(x-1)压缩,这样的话我们可以保证,每个二进制上代表的那个数字是1就代表存在这个属性。
AC_Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 #define rep(i,first,last) for(ll i=first;i<=last;i++) 6 #define dep(i,first,last) for(ll i=first;i>=last;i--) 7 ll n,m,q,x,y,cnt; 8 double k; 9 ll vis[maxn]; 10 ll flag[maxn]; 11 void init(){//预处理一下每个数字的二进制中有几个1代表有几个属性 12 ll z; 13 rep(i,0,1023){ 14 z=i; 15 while(z){ 16 if(z&1)flag[i]++; 17 z>>=1; 18 } 19 } 20 } 21 22 signed main() 23 { 24 scanf("%lld%lld",&n,&m); 25 rep(i,1,n){ 26 scanf("%lld",&q); 27 y=0; 28 rep(j,1,q){ 29 scanf("%lld",&x); 30 y += (1<<(x-1));//每次输入q次x都要进行状态的压缩 31 } 32 vis[y]++;//对该集合压缩后用book记录与该集合相同的集合一共有几个,类似于桶排 33 } 34 scanf("%lf",&k); 35 init(); 36 rep(i,1,1023){ 37 rep(j,i,1023){ 38 //如果其中有一个集合不存在那么就continue 39 if( !vis[i]||!vis[j] )continue; 40 ll f1=i&j;//二进制与运算,得到结果为两个集合相交后的结果 41 ll f2=i|j;//并集的结果 42 double ff=1.0*flag[f1]/flag[f2]; 43 if( ff<k ) continue; 44 else{ 45 if( i==j ) cnt+=vis[i]*(vis[j]-1)>>1;//这里用了一个等差数列前n项和 n*(n-1)/2 46 else cnt+=vis[i]*vis[j]; 47 } 48 } 49 } 50 printf("%lld\n",cnt); 51 return 0; 52 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 #define lowbit(x) x&(-x) 6 #define rep(i,first,last) for(ll i=first;i<=last;i++) 7 #define dep(i,first,last) for(ll i=first;i>=last;i--) 8 ll n,m,q,x,y,cnt; 9 double k; 10 ll vis[maxn]; 11 ll flag[maxn]; 12 void init(){//预处理一下每个数字的二进制中有几个1代表有几个属性 13 ll z; 14 rep(i,0,1023){ 15 z=i; 16 while(z){ 17 flag[i]++; 18 z-=lowbit(z); 19 } 20 } 21 } 22 23 signed main() 24 { 25 scanf("%lld%lld",&n,&m); 26 rep(i,1,n){ 27 scanf("%lld",&q); 28 y=0; 29 rep(j,1,q){ 30 scanf("%lld",&x); 31 y += (1<<(x-1));//每次输入q次x都要进行状态的压缩 32 } 33 vis[y]++;//对该集合压缩后用book记录与该集合相同的集合一共有几个,类似于桶排 34 } 35 scanf("%lf",&k); 36 init(); 37 rep(i,1,1023){ 38 rep(j,i,1023){ 39 //如果其中有一个集合不存在那么就continue 40 if( !vis[i]||!vis[j] )continue; 41 ll f1=i&j;//二进制与运算,得到结果为两个集合相交后的结果 42 ll f2=i|j;//并集的结果 43 double ff=1.0*flag[f1]/flag[f2]; 44 if( ff<k ) continue; 45 else{ 46 if( i==j ) cnt+=vis[i]*(vis[j]-1)>>1;//这里用了一个等差数列前n项和 n*(n-1)/2 47 else cnt+=vis[i]*vis[j]; 48 } 49 } 50 } 51 printf("%lld\n",cnt); 52 return 0; 53 }
参考博客:点这里