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 }

参考博客:点这里

原文地址:https://www.cnblogs.com/wsy107316/p/12367669.html

时间: 2024-07-31 18:08:49

Sleep Buddies (二进制状态压缩)的相关文章

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径(二进制状态压缩) 题目描述:n个点的带权无向图,从0-n-1,求从起点0到终点n-1的最短Hamilton路径(Hamilton路径:从0-n-1不重不漏的每个点恰好进过一次) 题解:二进制状态压缩算法\(O(2^n*n^2)\),需要记录当前经过了哪些点,当前在哪个位置.\(f[i][j]\) ? \(i\)转化为二进制每一位代表是否经过该点,\(j\)表示当前位于j这个点 #include <iostream> #include <cstring> u

二进制状态压缩及位运算

位运算符: 与(&),或(|),非(~), 异或(^); 移位运算: 1.左移:在二进制表示下把数字同时向左移动,低位以0填充,高位越界后舍弃 1 << n = 2^n, n << 1 = 2n 2.算术右移:在二进制补码表示下把数字同时向右移动,高位以符号位填充,低位越界后舍弃 n >> 1 = n/2.0(向下取整) eg:(-3)>> 1 = -2, 3 >> 1 = 1;  二进制状态压缩,是指将一个n位的 bool 数组用 n

皮卡丘的梦想2(线段树+二进制状态压缩)

Description 一天,一只住在 501 实验室的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘. 金桔告诉他需要进化石才能进化,并给了他一个地图,地图上有 n 个小镇,他需要从这些小镇中收集进化石. 接下来他会进行 q 次操作,可能是打听进化石的信息,也可能是向你询问第 l 个小镇到第 r 个小镇之间的进化石种类. 如果是打听信息,则皮卡丘会得到一个小镇的进化石变化信息,可能是引入了新的进化石,也可能是失去了全部的某种进化石. 如果是向

POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成

昨天晚上12点刷到的这个题,一开始一位是BFS,但是一直没有思路.后来推了一下发现只需要依次枚举第一行的所有翻转状态然后再对每个情况的其它田地翻转进行暴力dfs就可以,但是由于二进制压缩学的不是很透,一直有小问题,下面我还会讲子集生成的相关方法,有兴趣的同学可以继续关注. 本题大意:一块地,有黑(1)白(0)之分,牛每次踩踏使得当前块以及四连块都变色,问当牛如何踩时使得地都变白并且求出最小踩踏次数和踩踏路径的最小字典序时的踩踏地图. 本题思路:由于同一块地被翻两次都会回到原来的状态,所以只需要对

二进制状态压缩:应用及例题

1.位运算:https://www.cnblogs.com/yrjns/p/11246163.html 符号 描述 运算规则 & 与 两个位都为1时,结果才为1 | 或 两个位都为0时,结果才为0 ^ 异或 两个位相同为0,相异为1 ~ 取反 0变1,1变0 << 左移 各二进位全部左移若干位,高位丢弃,低位补0 >> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) Tips: (1)&a

BFS+二进制状态压缩 hdu-1429

好久没写搜索题了,就当练手吧. vis[][][1025]第三个维度用来维护不同key持有状态的访问情况. 对于只有钥匙没有对应门的位置,置为'.',避免不必要的状态分支. // // main.cpp // hdu_1429 // // Created by Luke on 16/10/8. // Copyright © 2016年 Luke. All rights reserved. // #include <iostream> #include <string> #inclu

二进制状态压缩相关操作

取出整数n在二进制表示下的第k位:(n>>k)&1 取出整数n在二进制表示下的第0~k-1位(后k位):n&((1<<k)-1) 把整数n在二进制表示下的第k位取反:n^(1<<k) 对整数n在二进制表示下的第k位赋值1:n|(1<<k) 对整数n在二进制表示下的第k位赋值0:n&(~(1<<k)) 原文地址:https://www.cnblogs.com/Mr94Kevin/p/10376623.html

Count Color (线段树区间染色?二进制状态压缩)

题目链接:https://vjudge.net/problem/POJ-2777 题意: 有L个画板,30种颜色,o个操作:P a b :询问a-b 种有多少种颜色不同的,C  a b c:把a-b全部涂成c的颜色(覆盖掉) 1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #in

HDU 3001 Travelling(状态压缩DP+三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费. 解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了.还有注意: ①开始要将n个起点初始化,dp[bit