Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4036
Solution
注:下面的
⨂
⨂
和幂,如果运算的对象是序列,则表示或卷积。
(即
hk=∑i OR j=kfi×gj
h
k
=
∑
i
OR
j
=
k
f
i
×
g
j
)
同时下面
p[S]
p
[
S
]
表示选数
S
S
的概率,即题目中的输入。
考虑 表示操作了
i
i
次之后数变成 的概率。
那么容易得到
f0,0=1
f
0
,
0
=
1
以及:
根据或卷积的定义,易得 fi=pi f i = p i 。
于是,我们设 res[S∈[0,2n)] r e s [ S ∈ [ 0 , 2 n ) ] 为变成 S S 的期望步数。
那么我们得到:
我们对 p p 求快速莫比乌斯变换 。
转化成:
将 res′ r e s ′ 求快速莫比乌斯反演后,答案为 res[2n−1] r e s [ 2 n − 1 ] 。
无解的情况:如果无解,那么对于任意的 i∈[0,∞) i ∈ [ 0 , ∞ ) 都满足 fi,2n−1=0 f i , 2 n − 1 = 0 ,这时候就能推出 res[2n−1]=0 r e s [ 2 n − 1 ] = 0 。故当 res[2n−1]=0 r e s [ 2 n − 1 ] = 0 时无解。
复杂度 O(2nn) O ( 2 n n ) 。
Code
代码非常短。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
const int N = 1048888;
const double eps = 1e-8;
int n, Cm;
double f[N];
void FMT(double *f, int op)
{
int i, j;
For (i, 1, n) For (j, 0, Cm)
if (!((j >> i - 1) & 1))
f[j | (1 << i - 1)] += f[j] * op;
}
int main()
{
int i;
cin >> n;
Cm = (1 << n) - 1;
For (i, 0, Cm) scanf("%lf", &f[i]);
FMT(f, 1);
For (i, 0, Cm)
f[i] = fabs(f[i] - 1.0) < eps ? 0 : -1.0 / (1.0 - f[i]);
FMT(f, -1);
if (f[Cm] < eps) puts("INF");
else printf("%.10lf\n", f[Cm]);
return 0;
}