CF698C

这又是什么毒瘤.....

解:把操作序列倒着来,就是考虑前k个入队的元素了。显然这样每个元素的概率不变。

状压。设fs表示当前元素为s的概率。

每次转移的时候选择一个不在s中的元素,作为下一个加入的元素。注意实际上有可能选择到在s中的元素。

然后我们设选择到s中元素的概率为x。

我们可能第一次就选到i,也有可能第2次选到,第3次选到......

概率分别是pi,x * pi,x2 * pi,......

无限求和有pi / (1 - x)。

所以最后转移的时候就是fs * pi * / (1 - x)

记得判断有用元素不足k的时候直接输出。

 1 #include <bits/stdc++.h>
 2 
 3 const int N = 25, M = 1200010;
 4 
 5 double p[N], f[M], ans[N], P[M];
 6 int n, k, wp[M], cnt[M];
 7 
 8 inline void out(int x) {
 9     for(int i = n - 1; i >= 0; i--) printf("%d", (x >> i) & 1);
10     puts("");
11     return;
12 }
13 
14 int main() {
15     int Cnt = 0;
16     scanf("%d%d", &n, &k);
17     for(int i = 0; i < n; i++) {
18         scanf("%lf", &p[i]);
19         if(p[i] > 0) Cnt++;
20     }
21     if(Cnt < k) {
22         for(int i = 0; i < n; i++) {
23             if(p[i] > 0) printf("1 ");
24             else printf("0 ");
25         }
26         return 0;
27     }
28 
29 
30     int lm = (1 << n);
31     for(int i = 0; i < n; i++) wp[1 << i] = i;
32     for(int i = 1; i < lm; i++) {
33         cnt[i] = 1 + cnt[i - (i & (-i))];
34         P[i] = P[i - (i & (-i))] + p[wp[i & (-i)]];
35     }
36     f[0] = 1;
37     for(int i = 0; i < lm; i++) {
38         //out(i);
39         if(cnt[i] == k) {
40             for(int s = 0; s < n; s++) {
41                 if(i & (1 << s)) {
42                     ans[s] += f[i];
43                 }
44             }
45             continue;
46         }
47         if(cnt[i] > k) continue;
48         for(int s = 0; s < n; s++) {
49             if((i >> s) & 1) continue;
50             f[i | (1 << s)] += f[i] * p[s] / (1 - P[i]);
51         }
52     }
53 
54     for(int i = 0; i < n; i++) printf("%.8f ", ans[i]);
55     return 0;
56 }
AC代码
原文地址:https://www.cnblogs.com/huyufeifei/p/10484317.html