[CodeForces-708E]Student's Camp
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CodeForces-708E]Student's Camp相关的知识,希望对你有一定的参考价值。
题目大意:
一个n*m的墙,被吹k天风,每块靠边的砖都有p的概率被吹掉。
如果上下两行没有直接相连的地方,我们则认为这一堵墙已经倒塌。
问最后墙不倒塌的概率(模意义)。
思路:
动态规划。
用f[i][j][k]表示到了第i层,只剩下j~k的砖头并且不倒塌的概率。
则f[i][j][k]=sum{f[i-1][l][r]|[l,r]与[j,k]有交集}*这一层只剩[l,r]的概率。
概率可以O(n)预处理,接下来要枚举i,j,k,l,r,所以是O(m^4n)的。
接下来考虑预处理sum{f[i-1][l][r]|[l,r]与[j,k]有交集}。
显然有交集的概率=总概率-没有交集的概率=总概率-r<i的概率-j<l的概率。
而这些概率都可以一边转移一边推。
这样转移的时候就不需要考虑具体的l,r,是O(m^2n)的。
数组1500^3还会爆,考虑滚动数组,勉强开下,反正还是TLE。
正解是一个很神奇的O(mn)算法。(并不是很懂)
考虑用f[i][k]表示前面的f[i][1][k]~f[i][k][k]的和。
然后预处理所有关于j的前缀和。
然后递推式就只与i,k有关了。
1 #include<cstdio> 2 #include<cctype> 3 typedef long long int64; 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^‘0‘; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 9 return x; 10 } 11 const int mod=1e9+7; 12 const int N=1501,M=1501,K=100001; 13 void exgcd(const int &a,const int &b,int &x,int &y) { 14 if(!b) { 15 x=1; 16 y=0; 17 return; 18 } 19 exgcd(b,a%b,y,x); 20 y-=a/b*x; 21 } 22 inline int inv(const int64 &x) { 23 int tmp,ret; 24 exgcd(x,mod,ret,tmp); 25 return (ret+mod)%mod; 26 } 27 int f[2][M]; 28 int p[K],q[K]; 29 int fact[K],tcaf[K]; 30 int k; 31 inline int calc(const int &x) { 32 return (int64)fact[k]*tcaf[k-x]%mod*tcaf[x]%mod*p[x]%mod*q[k-x]%mod; 33 } 34 int main() { 35 int n=getint(),m=getint(); 36 int a=getint(),b=getint(); 37 k=getint(); 38 fact[0]=1; 39 for(register int i=1;i<=k;i++) { 40 fact[i]=(int64)fact[i-1]*i%mod; 41 } 42 tcaf[k]=inv(fact[k]); 43 for(register int i=k-1;~i;i--) { 44 tcaf[i]=(int64)tcaf[i+1]*(i+1)%mod; 45 } 46 p[0]=q[0]=1; 47 p[1]=q[1]=inv(b); 48 p[1]=(int64)p[1]*a%mod; 49 q[1]=(int64)q[1]*(b-a)%mod; 50 for(register int i=2;i<=k;i++) { 51 p[i]=(int64)p[i-1]*p[1]%mod; 52 q[i]=(int64)q[i-1]*q[1]%mod; 53 } 54 f[0][m]=1; 55 for(register int i=1;i<=n;i++) { 56 int s1=0,s2=0; 57 for(register int j=0;j<=m;j++) { 58 f[i&1][j]=((int64)s1*(f[!(i&1)][m]-f[!(i&1)][m-j])-s2)%mod*calc(m-j)%mod; 59 s1=(s1+calc(j))%mod; 60 s2=(s2+(int64)f[!(i&1)][j]*calc(j))%mod; 61 } 62 for(register int j=1;j<=m;j++) { 63 f[i&1][j]=(f[i&1][j]+f[i&1][j-1])%mod; 64 } 65 } 66 printf("%d\n",(f[n&1][m]+mod)%mod); 67 return 0; 68 }
以上是关于[CodeForces-708E]Student's Camp的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 708A Letters Cyclic Shift
CodeForces 708B Recover the String
题解Recover the String Codeforces 708B
codeforces708b// Recover the String //AIM Tech Round 3 (Div. 1)