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 }

参考博客:点这里

posted @ 2020-02-26 16:34  swsyya  阅读(149)  评论(0编辑  收藏  举报

回到顶部