洛谷 P3175 [HAOI2015]按位或 fwt

题目描述

刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal的or)操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1。问期望多少秒后,你手上的数字变成2^n-1。

输入输出格式

输入格式:
第一行输入n表示n个元素,第二行输入2^n个数,第i个数表示选到i-1的概率

输出格式:
仅输出一个数表示答案,绝对误差或相对误差不超过1e-6即可算通过。如果无解则要输出INF

输入输出样例

输入样例#1:
2
0.25 0.25 0.25 0.25
输出样例#1:
2.6666666667
说明

对于100%的数据,n<=20

分析:
p1(i),i[0,2n) p 1 ( i ) , i ∈ [ 0 , 2 n ) 为一次走到 i i 的概率,那么,小于等于两次走到i的概率就是,

p2(i)=j|k=ip1(j)p1(k) p 2 ( i ) = ∑ j | k = i p 1 ( j ) ∗ p 1 ( k )

多次的也可以推出。
在第 k k 次走到i的概率为 pk(i)pk1(i) p k ( i ) − p k − 1 ( i ) ,所以到 i i 的期望f(i)
f(i)=k=1infk(pk(i)pk1(i)) f ( i ) = ∑ k = 1 i n f k ∗ ( p k ( i ) − p k − 1 ( i ) )

f(2n1) f ( 2 n − 1 ) 就是答案。

有一个叫做莫比乌斯变换的东西,大概就是设 f^(i)=jif(j) f ^ ( i ) = ∑ j ⊂ i f ( j )
然后就是一堆乱七八糟的东西。
我们回忆对或运算的 Fwt F w t Dwt D w t

Fwt(A)=(Fwt(A0),Fwt(A0+A1)) F w t ( A ) = ( F w t ( A 0 ) , F w t ( A 0 + A 1 ) )

Dwt(A)=(Dwt(A0),Dwt(A1A0)) D w t ( A ) = ( D w t ( A 0 ) , D w t ( A 1 − A 0 ) )

观察 Fwt F w t ,当 i i 从后面起第j位为 1 1 时,就加上了除了这位为0,其他位全与 i i 相同的数。而这些数又加上他们的自己不同的数。也就是说,Fwt A A 数组的第i位,就是他的子集的和,也就是 f^(i) f ^ ( i ) 。这两个是同一个东西。
那么那些什么莫比乌斯变换与反演,完全可以看作是 Fwt F w t 操作和 Dwt D w t 操作。

那么我们再来计算答案,先把 p1(i) p 1 ( i ) Fwt F w t 操作得到 p^1(i) p ^ 1 ( i ) 。这两个式子其实是一个东西,就好像点值多项式和系数多项式的区别,所以,

f^(i)=k=1infk(p^k(i)p^k1(i)) f ^ ( i ) = ∑ k = 1 i n f k ∗ ( p ^ k ( i ) − p ^ k − 1 ( i ) )

=(p^1(i)p^0(i))+2(p^2(i)p^1(i))+....... = ( p ^ 1 ( i ) − p ^ 0 ( i ) ) + 2 ∗ ( p ^ 2 ( i ) − p ^ 1 ( i ) ) + . . . . . . .

化简一下得到,
=infp^inf(i)...p^1(i)p^0(i) = i n f ∗ p ^ i n f ( i ) − . . . − p ^ 1 ( i ) − p ^ 0 ( i )

其中,除了第一项的系数是 inf i n f ,其他全是 1 1
因为p^1(i)[0,1],且因为 p0(0)=1,p0(x)=0,(x>0) p 0 ( 0 ) = 1 , p 0 ( x ) = 0 , ( x > 0 ) ,所以 p^0(i)=1(x>=0) p ^ 0 ( i ) = 1 ( x >= 0 )

因此,当 p^1(i)=1 p ^ 1 ( i ) = 1 时,那么 p^k(i)=1 p ^ k ( i ) = 1 ,第一项为 inf i n f ,后面项为 inf − i n f ,即 f^(i)=0 f ^ ( i ) = 0
p^1(i)[0,1) p ^ 1 ( i ) ∈ [ 0 , 1 ) 时,

f^(i)=infp^inf(i)(+...+p^1(i)+p^0(i)) f ^ ( i ) = i n f ∗ p ^ i n f ( i ) − ( + . . . + p ^ 1 ( i ) + p ^ 0 ( i ) )

=infp^inf(i)p^inf(i)p^0(i)p^1(i)1 = i n f ∗ p ^ i n f ( i ) − p ^ i n f ( i ) − p ^ 0 ( i ) p ^ 1 ( i ) − 1

因为 p^1(i)[0,1) p ^ 1 ( i ) ∈ [ 0 , 1 ) ,所以 p^inf(i)=0 p ^ i n f ( i ) = 0
所以 f^(i)=1p^1(i)1 f ^ ( i ) = 1 p ^ 1 ( i ) − 1

综上,我们先给 p p 跑一次Fwt,然后求出 f^ f ^ ,然后给 f^ f ^ Dwt D w t ,就可以求出 f f 了。设k=2n,复杂度是 O(klogk) O ( k ∗ l o g k ) ,和 O(n2n) O ( n ∗ 2 n ) 是一样的。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

const int maxn=1048580;
const double limit=1e-12;

using namespace std;

int n;
double p[maxn];

void fwt(double *a,int l,int r)
{
    if (l==r) return;
    int n=(r-l+1)/2,mid=l+n;
    fwt(a,l,mid-1);
    fwt(a,mid,r);
    for (int i=l;i<mid;i++)
    {
        double u=a[i],v=a[i+n];
        a[i+n]=u+v;
    }
}

void dwt(double *a,int l,int r)
{
    if (l==r) return;
    int n=(r-l+1)/2,mid=l+n;
    dwt(a,l,mid-1);
    dwt(a,mid,r);
    for (int i=l;i<mid;i++)
    {
        double u=a[i],v=a[i+n];
        a[i+n]=v-u;
    }
}

int main()
{
    scanf("%d",&n);
    n=1<<n;
    for (int i=0;i<n;i++) scanf("%lf",&p[i]);
    fwt(p,0,n-1);   
    for (int i=0;i<n;i++)
    {
        if (abs(p[i]-1)<limit) p[i]=0;
                        else p[i]=1/(p[i]-1);
    }
    dwt(p,0,n-1);
    if (abs(p[n-1])<limit) printf("INF");
                      else printf("%.8lf",p[n-1]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值