[BZOJ4036][HAOI2015]按位或(FMT?FWT?)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=4036

Solution

注:下面的 和幂,如果运算的对象是序列,则表示或卷积。
(即 h k = i  OR  j = k f i × g j
同时下面 p [ S ] 表示选数 S 的概率,即题目中的输入。
考虑 f i , S 表示操作了 i 次之后数变成 S 的概率。
那么容易得到 f 0 , 0 = 1 以及:

f i , S = A  OR  B = S f i 1 , A p B

根据或卷积的定义,易得 f i = p i
于是,我们设 r e s [ S [ 0 , 2 n ) ] 为变成 S 的期望步数。
那么我们得到:
r e s = i = 1 i × ( f i f i 1 )

= i = 1 f i = i = 1 p i

我们对 p 求快速莫比乌斯变换 p
转化成:
r e s [ S ] = { 1 p [ S ] 1 p [ S ] 1 0 p [ S ] = 1

r e s 求快速莫比乌斯反演后,答案为 r e s [ 2 n 1 ]
无解的情况:如果无解,那么对于任意的 i [ 0 , ) 都满足 f i , 2 n 1 = 0 ,这时候就能推出 r e s [ 2 n 1 ] = 0 。故当 r e s [ 2 n 1 ] = 0 时无解。
复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/82227894