传球70分做法

题目描述

这里写图片描述
70分n<=1000

dp

容易看出被攻略的是连续一段。
设dp[l,r,0~1]表示攻略了[l,r],此时球在哪个端点。
我们需要预处理f与g。
f[i]表示从一个结点走至多走到顺时针走i步的位置情况下走到逆时针走1步的位置的概率。
假设顺时针走1步概率为p。
f[i]=1p+pf[i1]f[i]
1-p的概率直接走到,否则我们首先用f[i-1]概率走回来,再用f[i]概率走过去,移一下项 f[i]=1p1pf[i1]
然后可以递推出f。
g的意义与f类似,就是顺逆时针的问题。
注意到例如f[l,r,0],要转移到f[l,r+1,1],需要走好多步,概率应该是g[0]*g[1]*g[2]……
因此还需要预处理f与g的前缀积。
然后就解决了。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef double db;
const db eps=0.0000001;
const int maxn=1000+10;
db dp[maxn][maxn][2];
db f[maxn],g[maxn],num[maxn],sum[maxn];
db p,q,ans;
int i,j,k,l,t,n,m;
int main(){
    freopen("pass.in","r",stdin);freopen("pass.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    p=(db)k/1000000000;q=1-p;
    f[0]=1-p;
    fo(i,1,n)
        f[i]=(1-p)/(1-p*f[i-1]);
    sum[0]=f[0];
    fo(i,1,n) sum[i]=sum[i-1]*f[i];
    g[0]=1-q;
    fo(i,1,n)
        g[i]=(1-q)/(1-q*g[i-1]);
    num[0]=g[0];
    fo(i,1,n) num[i]=num[i-1]*g[i];
    dp[0][1][1]=p;
    dp[n-1][0][0]=q;
    fo(l,2,n-1)
        fd(i,n,n-l+1){
            j=(i+l-1)%n;
            dp[i-1][j][0]+=dp[i%n][j][0]*f[l-1];
            dp[i%n][j+1][1]+=dp[i%n][j][0]*num[l-1];
            dp[i-1][j][0]+=dp[i%n][j][1]*sum[l-1];
            dp[i%n][j+1][1]+=dp[i%n][j][1]*g[l-1];
        }
    if (!m) printf("0\n");
    else{
        ans=dp[(m+1)%n][m][1]+dp[m][m-1][0];
        printf("%.12e\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值