[LnOI2019]加特林轮盘赌

Luogu5249

轮流开枪打一个环上的人 , 每次p的概率打死,p始终相同,从第1个人开始 , 求第k个人成为唯一幸存者的概率

官方题解先递推出\(f[n]\) , \(f[1]\)用到\(f[n]\) , 套上一个\(n\)的循环 , 总共是\(O(n^2)\)

\(f1[i]\)表示\([1,k-1]\)\(i\)轮以内全死的概率 , \(f2[i]\)表示\([k+1,n]\)\(i\)轮以内全死的概率 ,
\(s[i]\)表示某一个人在\(i\)轮以内死掉的概率 , 易知\(s[i]=1-(1-p)^i\)

\(f1[i]=s[i]^{(k-1)}\)
\(f2[i]=s[i]^{(n-k)}\)

枚举第\(k\)个人第\(i\)轮死 , \(ans=\sum{f1[i]*f2[i-1]*(s[i]-s[i-1])}\)

\(10^4\)个人枚举\(10^6\)轮就差不多了 , \(f1\)\(f2\)的预处理是\(O(nl_{og}n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,k;
double p,sp,ans,s[N],pw1[N],pw2[N];
double qpow(double a,int b)
{
    double ret=1;
    while(b)
    {
        if(b&1)ret*=a;
        a*=a,b>>=1;
    }
    return ret;
}
int main()
{
    cin>>p>>n>>k;
    if(n==1){cout<<1;return 0;}
    for(int i=1;i<=1e5;i++)s[i]=1-qpow(1-p,i);
    for(int i=1;i<=1e5;i++)pw1[i]=qpow(s[i],k-1),pw2[i]=qpow(s[i],n-k);
    for(int i=1;i<=1e5;i++)
    if(k==n)ans+=pw1[i]*(s[i]-s[i-1]);
    else if(k==1)ans+=pw2[i-1]*(s[i]-s[i-1]);
    else ans+=pw1[i]*pw2[i-1]*(s[i]-s[i-1]);
    printf("%0.9f",ans);
}

猜你喜欢

转载自www.cnblogs.com/lizehon/p/10627553.html