zoukankan      html  css  js  c++  java
  • 【CF708E】Student's Camp 组合数+动态规划

    【CF708E】Student's Camp

    题意:有一个n*m的网格,每一秒钟,所有左面没有格子的格子会有p的概率消失,右面没有格子的格子也会有p的概率消失,问你t秒钟后,整个网格的上边界和下边界仍然连通的概率是多少。

    $n,mle 1500,tle 10^6$。

    题解:首先我们可以预处理出c数组,c[i]表示t秒钟后左边恰有i个格子消失的概率,这个用组合数算一算即可。又因为每一行的本质是相同的,所以令某一行最终剩下的格子是[l,r]的概率就是c[l-1]*c[m-r]。

    然后考虑一个naive的DP。f[i][l][r]表示第i行剩下的是[l,r],且第i行与上边界连通的概率。不难得到转移方程,并用前缀和优化可得:

    $f[i][l][r]=(sr[i-1][m]-gr[i-1][l-1]-gl[i-1][r+1])cdot c[l-1]cdot c[r-m]$

    其中$sr[i][r]=sumlimits_{l=1}^rf[i][l][r],gr[i][r]=sumlimits_{j=1}^rsr[i][j]$。

    但是这个转移是$O(nm^2)$的,所以我们不能这么设状态。有一个套路:把f[i][l][r]换成fl[i][l]和fr[i][r]试试?

    具体推导过程留给读者。时间复杂度$O(nm)$。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const ll P=1000000007;
    
    int n,m,t;
    ll p;
    ll ine[100010],jc[100010],jcc[100010],p1[100010],p2[100010];
    ll fr[2][1510],fl[2][1510],sr[2][1510],sl[2][1510],gl[2][1510],gr[2][1510],sc[1510],c[1510];
    inline ll pm(ll x,ll y)
    {
    	ll z=1;
    	while(y)
    	{
    		if(y&1)	z=z*x%P;
    		x=x*x%P,y>>=1;
    	}
    	return z;
    }
    inline ll C(int a,int b)
    {
    	if(a<b)	return 0;
    	return jc[a]*jcc[b]%P*jcc[a-b]%P;
    }
    inline ll calc(int a)
    {
    	return C(t,a)*p1[a]%P*p2[t-a]%P;
    }
    
    int main()
    {
    	ll a,b;
    	int i,j,d=0;
    	scanf("%d%d%lld%lld%d",&n,&m,&a,&b,&t),p=a*pm(b,P-2)%P;
    	ine[0]=ine[1]=jc[0]=jc[1]=jcc[0]=jcc[1]=1;
    	for(i=2;i<=t;i++)	ine[i]=P-(P/i)*ine[P%i]%P,jc[i]=jc[i-1]*i%P,jcc[i]=jcc[i-1]*ine[i]%P;
    	for(p1[0]=p2[0]=i=1;i<=t;i++)	p1[i]=p1[i-1]*p%P,p2[i]=p2[i-1]*(1-p)%P;
    	for(i=0;i<=m;i++)	c[i]=calc(i);
    	for(i=1;i<=m;i++)
    		for(j=1;j<=i;j++)	a=c[j-1]*c[m-i]%P,fr[0][i]=(fr[0][i]+a)%P,fl[0][j]=(fl[0][j]+a)%P;
    	for(i=1;i<=m;i++)	sr[0][i]=(sr[0][i-1]+fr[0][i])%P;
    	for(i=m;i>=1;i--)	sl[0][i]=(sl[0][i+1]+fl[0][i])%P;
    	for(i=1;i<=m;i++)	gr[0][i]=(gr[0][i-1]+sr[0][i]*c[i])%P;
    	for(i=m;i>=1;i--)	gl[0][i]=(gl[0][i+1]+sl[0][i]*c[m-i+1])%P;
    	for(i=0;i<=m;i++)	sc[i]=(sc[i-1]+c[i])%P;
    	for(i=2;i<=n;i++)
    	{
    		d^=1;
    		memset(fl[d],0,sizeof(fl[d])),memset(fr[d],0,sizeof(fr[d]));
    		memset(sl[d],0,sizeof(sl[d])),memset(sr[d],0,sizeof(sr[d]));
    		for(j=1;j<=m;j++)
    		{
    			fr[d][j]=c[m-j]*((sr[d^1][m]-sl[d^1][j+1])*sc[j-1]%P-gr[d^1][j-1])%P;
    			fl[d][j]=c[j-1]*((sr[d^1][m]-sr[d^1][j-1])*sc[m-j]%P-gl[d^1][j+1])%P;
    		}
    		for(j=1;j<=m;j++)	sr[d][j]=(sr[d][j-1]+fr[d][j])%P;
    		for(j=m;j>=1;j--)	sl[d][j]=(sl[d][j+1]+fl[d][j])%P;
    		for(j=1;j<=m;j++)	gr[d][j]=(gr[d][j-1]+sr[d][j]*c[j])%P;
    		for(j=m;j>=1;j--)	gl[d][j]=(gl[d][j+1]+sl[d][j]*c[m-j+1])%P;
    	}
    	printf("%lld",(sr[d][m]+P)%P);
    	return 0;
    }
  • 相关阅读:
    已知自然数A、B不互质,A、B最大公约数和最小公倍数之和为35,那么A+B的最小值是多少?
    mysql null字段 空字段 查询效率
    sql注入和网站攻击思路
    软件服务新时代:开源软件的盈利模式
    eclipse maven插件配置,jdk全局版本调整
    spring事务(isolation隔离级别,propagation事务传播属性)
    GBDT 算法
    博客园的 “随笔、文章、新闻、日记”有啥区别
    1.3 Java中的标识符和关键字
    1.1 Java 的概述
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8504058.html
Copyright © 2011-2022 走看看