BZOJ4036 按位或

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

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

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

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

把所有的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代码

第二种:Min-Max容斥。

设fs为把状态s的所有元素中至少一个变成1的期望次数。

同样是对步数0~∞求和,每次的概率是(没选到)i。最后Min-Max容斥统计答案。

 

 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 2
21 0.25 0.25 0.25 0.25
22 
23 */
24 int main() {
25     scanf("%d", &n);
26     lm = 1 << n;
27     for(int i = 0; i < lm; i++) {
28         scanf("%lf", &p[i]);
29         w[i] = p[i];
30         if(i) {
31             cnt[i] = 1 + cnt[i - (i & (-i))];
32         }
33         if(i > 1) {
34             pw[i] = pw[i >> 1] + 1;
35         }
36     }
37     FWT_or(p, lm, 1);
38     for(int i = 0; i < lm; i++) {
39         if(i != lm - 1 && p[i] > 1 - eps) {
40             printf("INF\n");
41             return 0;
42         }
43         //printf("p %d = %lf \n", i, p[i]);
44         f[i] = 1.0 / (1 - p[(lm - 1) ^ i]);
45     }
46     //FWT_or(f, lm, -1);
47     double ans = 0;
48     for(int i = 1; i < lm; i++) {
49         if(cnt[i] & 1) ans += f[i];
50         else ans -= f[i];
51     }
52     printf("%.10f\n", ans);
53     return 0;
54 }
AC代码

 

转载于:https://www.cnblogs.com/huyufeifei/p/10721835.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值