beginend

只要在路上,就没有到不了的远方

Codeforces 708E Student's Camp 动态规划

题意

现在有m+2行砖块,每行有n个,其中最上面和最下面两行都是不可被摧毁的。现在每天白天会吹从左侧到右侧的风,晚上会吹从右侧到左侧的风。若一个砖块被风吹到,则会有p的概率被摧毁。问k天后存在一条从最上面一行到最下面一行的四连通路径的概率。
n,m1500

分析

先考虑暴力,我们设dp[t,l,r]表示前t行已经被处理完,且第t行存在的砖块是[l,r]的概率。
不难得到转移

dp[t,l,r]=pl,rdp[t1,pl,pr]

其中满足[pl,pr][l,r]有交,且pl,r表示某一行k天后剩下的砖块是[l,r]的概率。
但这样做是O(n5)的,考虑优化。
dpr[t,r]=lrdp[t,l,r]

sum_dpr[t,r]=ardpr[t,a]

容斥一下不难得到
dp[t,l,r]=pl,r(sum_dpr[t1,n]sum_dpr[t1,l1]sum_dpr[t1,nr])

这样就可以做到O(n3)了。
继续观察可以发现
dpr[t,r]=lrpl,r(sum_dpr[t1,n]sum_dpr[t1,l1]sum_dpr[t1,nr])

那么我们只要在枚举r的过程中维护一下前两项的和,就可以对dpr[t,r]进行O(1)转移。
最后sum_dpr[m,n]就是答案了。
时间复杂度为O(n2)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;

const int N=1505;
const int MOD=1000000007;

int n,m,a,b,k,jc[100005],ny[100005],pre[N],f[N][N],s[N][N],p[N];

int ksm(int x,int y)
{
    if (y<0) return 0;
    int ans=1;
    while (y)
    {
        if (y&1) ans=(LL)ans*x%MOD;
        x=(LL)x*x%MOD;y>>=1;
    }
    return ans;
}

int C(int n,int m)
{
    if (n<m) return 0;
    return (LL)jc[n]*ny[m]%MOD*ny[n-m]%MOD;
}

int main()
{
    scanf("%d%d%d%d%d",&n,&m,&a,&b,&k);
    a=(LL)a*ksm(b,MOD-2)%MOD;
    jc[0]=jc[1]=ny[0]=ny[1]=1;
    for (int i=2;i<=k;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
    for (int i=2;i<=k;i++) ny[i]=(LL)ny[i-1]*ny[i]%MOD;
    for (int i=1;i<=m;i++) p[i]=(LL)ksm(a,i-1)*ksm(1+MOD-a,k-i+1)%MOD*C(k,i-1)%MOD,pre[i]=(pre[i-1]+p[i])%MOD;
    f[0][m]=s[0][m]=1;
    for (int i=1;i<=n;i++)
    {
        int w=0;
        for (int j=1;j<=m;j++)
        {
            (w+=(LL)p[j]*(s[i-1][m]+MOD-s[i-1][j-1])%MOD)%=MOD;
            f[i][j]=(LL)(w+MOD-(LL)s[i-1][m-j]*pre[j]%MOD)*p[m-j+1]%MOD;
            s[i][j]=(s[i][j-1]+f[i][j])%MOD;
        }
    }
    printf("%d",s[n][m]);
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/80689773
个人分类: 动态规划
想对作者说点什么? 我来说一句

动态规划题解

2013年12月22日 1KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭