bitset刷题记录
大佬的bitset用法小结 https://www.cnblogs.com/zwfymqz/p/8696631.html
BZOJ3687简单题
题意:求子集的算术和的异或和,子集大小为n(n<=1000),所有数和sum<=2000000
- 求子集和可以用01背包的那个动规,f[i]表示有多少个子集和为i 。时间复杂度O(n*sum)
- 但是只求异或和就只表示奇偶性,所以bit[i]表示和为i的子集个数的奇偶性。
- 时间复杂度降为O(n*sum/机器字长)
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 10010 3 #define f(a,b) for(int i=a; i<=b; i++) 4 5 using namespace std; 6 typedef long long ll; 7 8 int main(){ 9 bitset<2000000> bit; 10 bit[0] = 1; 11 int n, x; 12 int ans = 0; 13 cin >> n; 14 f(1, n) { 15 scanf("%d", &x); 16 bit ^= (bit << x); 17 } 18 f(1,2000000) if(bit[i]) ans^=i; 19 cout << ans << endl; 20 return 0; 21 }
HDU5036Explosion
- 求期望:先求出有多少个点能够到达点i :cnt[i],期望就等于$\sum_{i=1}^n cnt[i]$
- 这样求是因为:考虑使用在第i个门上的炸弹数量期望,要把第i个门弄开,可以有cnt[i]中爆炸选择,所以直接炸i的概率就是 1/cnt[i] ,根据期望的线性性质,所有门求和即得总的炸弹数量
- 但是这样还是不是很清楚为啥就是期望,因为可能每个门的出现不是均匀的,,,有木有路过的大佬能说一下呀~
- 所以用bitset优化floyd求传统闭包
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 1010 3 #define f(c, a, b) for (int c=a; c<=b; c++) 4 5 using namespace std; 6 int n; 7 bitset <nmax> d[nmax]; 8 9 void floyd(){ f(k, 1, n) f(i, 1, n) if(d[i][k]) d[i]|=d[k]; } 10 11 void init(){ f(i,1,n) { d[i].reset(); d[i][i]=1; } } 12 13 int main(){ 14 int t; 15 cin >> t; 16 f(cas, 1, t) { 17 scanf("%d", &n); 18 init(); 19 int ys, v; 20 double ans=0; 21 f(i, 1, n) { 22 scanf("%d", &ys); 23 f(j, 1, ys) { 24 scanf("%d", &v); 25 d[v][i] = 1; 26 } 27 } 28 floyd(); 29 f(i,1,n) ans += 1.0/d[i].count(); 30 printf("Case #%d: %.5lf\n", cas, ans); 31 } 32 return 0; 33 }