BZOJ4036 按位或

BZOJ4036 按位或

解:有两种做法......

第一种,按照秘密袭击coat的套路,我们只需要求出BZOJ4036 按位或即可。因为一种操作了i次的方案会被恰好计数i次。

那么这个东西怎么求呢?直接用FWT的思想,对于一个状态s,求出选择s所有子集的概率ps。那么第i次操作后是s的子集的概率就是psi

设fs表示第i次操作之后是s的子集的概率。

BZOJ4036 按位或

把所有的f求出来之后做一次IFWT即可。然后我们对于所有非全集求和。

参考资料

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 30, M = 1500010;
 4 const double eps = 1e-12;
 5 
 6 double f[M], p[M], w[M];
 7 int cnt[M], pw[M], n, lm;
 8 
 9 inline void FWT_or(double *a, int n, int f) {
10     for(int len = 1; len < n; len <<= 1) {
11         for(int i = 0; i < n; i += (len << 1)) {
12             for(int j = 0; j < len; j++) {
13                 a[i + len + j] += f * a[i + j];
14             }
15         }
16     }
17     return;
18 }
19 
20 int main() {
21     scanf("%d", &n);
22     lm = 1 << n;
23     for(int i = 0; i < lm; i++) {
24         scanf("%lf", &p[i]);
25         w[i] = p[i];
26         if(i) {
27             cnt[i] = 1 + cnt[i - (i & (-i))];
28         }
29         if(i > 1) {
30             pw[i] = pw[i >> 1] + 1;
31         }
32     }
33     FWT_or(p, lm, 1);
34     for(int i = 0; i < lm; i++) {
35         if(i != lm - 1 && p[i] > 1 - eps) {
36             puts("INF");
37             return 0;
38         }
39         f[i] = 1.0 / (1 - p[i]);
40     }
41     FWT_or(f, lm, -1);
42     double ans = 0;
43     for(int i = 0; i < lm - 1; i++) {
44         ans += f[i];
45     }
46     printf("%.10f\n", ans);
47     return 0;
48 }
AC代码

相关文章:

  • 2021-05-25
  • 2021-07-05
  • 2022-12-23
  • 2021-11-01
  • 2021-11-10
  • 2021-12-05
  • 2021-12-05
  • 2021-12-05
猜你喜欢
  • 2021-05-25
  • 2021-11-11
  • 2021-08-11
  • 2022-01-07
  • 2021-11-24
  • 2021-12-31
  • 2021-07-31
相关资源
相似解决方案