CF708E Student's Camp 题解
作者:互联网
状态优化+前缀和优化
Statement
有一个 \((n+2) \times m\) 的网格。
除了第一行和最后一行,其他每一行每一天最左边和最右边的格子都有 \(p\) 的概率消失。
求 \(k\) 天后,网格始终保持连通的概率。
\(n,m \le 1.5 \times 10^3\),\(k \le 10^5\),取模 \(10^9+7\)。
Solution
首先应该发现的是对于每一个行都是独立的,长什么样子全凭自己
同时也发现了对于一行而言,左右怎么削也是独立的,左边不会干扰右边,右边同理
可以想到设 \(f[i][l][r]\) 表示前 \(i\) 行连通,交集为 \([l,r]\) 的概率,有暴力转移:
为了方便起见,下面设 \(g[i]=\binom ki p^i(1-p)^{k-i}\)
\[f[i][l][r]=\binom k{l-1}\binom k{m-r}p^{m-r+l-1}(1-p)^{2k-m+r-l+1}\sum_{l^{\prime}\le r^{\prime},\max(l,l^{\prime})\le \min(r,r^{\prime})} dp[i-1][l^{\prime}][r^{\prime}]\\ =g[l-1]g[m-r]\sum dp[i-1][l^{\prime}][r^{\prime}] \]好,\(O(n^3)\) 状态,\(O(n^2)\) 转移,很有精神。
不管怎样,状态数都是要削的,不然削转移复杂度没有意义。
本题最为神仙的一步出现了,考虑到 \(f[i][l][\dots]\) 其实和 \(f[i][\dots][m-l+1]\) 等价(反正左边和右边都是独立的,那么左右就是对称的,换一下无所谓),
我们考虑直接改设 \(f[i][r]\) 表示前 \(i\) 行联通,交集为 \([\dots ,r]\) 的概率和
粗暴地,管都不管,直接先来一个
\[\sum_{r^{\prime}=1}^mf[i-1][r^{\prime}]\to f[i][r] \]考虑多算了什么东西,多算了
- \(r^{\prime}<l\) ,可以看作是所有以 \(l\) 为右端点的区间的贡献,也就是 \(\sum_\limits{j=1}^{l-1}f[i-1][j]\)
- \(r<l^{\prime}\),可以看作是所有以 \(r\) 为左端点的区间的贡献,对称一下,也就是 \(\sum_\limits{j=1}^{m-r}f[i-1][j]\)
所以枚举一下 \(l\),式子变成了这样:
\[f[i][r]=\sum_{l=1}^r g[l-1]g[m-r](\sum_{j=1}^mf[i-1][j]-\sum_\limits{j=1}^{l-1}f[i-1][j]-\sum_\limits{j=1}^{m-r}f[i-1][j]) \]暴力计算的话,状态数 \(O(n^2)\) ,转移 \(O(n^2)\) ,很好,干掉一个 \(O(n)\)
发现括号里面显然是一个前缀和的形式,记 \(F[j]=\sum_{k\le j} f[i-1][k]\)
\[f[i][r]=\sum_{l=1}^r g[l-1]g[m-r](F[m]-F[l-1]-F[m-r]) \]好了,转移 \(O(n)\) 了,但是这个式子显然还是很有优化的潜力的,从上面对算重部分的分析可以看出,其实我们真正需要枚举的 \(l\) 的部分只有 \(F[l-1]\) ,其他大致与 \(l\) 关系不是很大
运用小学知识拆括号并合并同类项:
\[f[i][r]=g[m-r]((F[m]-F[m-r])\sum _{l=1}^rg[l-1]-\sum_{l=1}^rg[l-1]F[l-1]) \]记 \(G[j]=\sum_{k\le j} g[k],FG[j]=\sum_{k\le j}g[j]F[j]\)
\[f[i][r]=g[m-r]\times ((F[m]-F[m-r])G[r-1]-FG[r-1]) \]好了,转移 \(O(1)\) 了,状态数 \(O(n^2)\),\(F,G,FG\) 复杂度也是 \(O(n^2)\)
总复杂度 \(O(n^2)\) (突然发现自己在分析复杂度的时候把 \(nm\) 混用了,无所谓)
本题的关键在于深入理解左右独立性质之后对于状态的精彩缩减,后续的前缀和优化可以在尝试性地拆括号后发现
Code
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int K = 1e5+5;
const int N = 3005;
char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
int s=0,w=1; char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
return s*w;
}
inline void inc(int &a,int b){a=a>=mod-b?a-mod+b:a+b;}
inline void dec(int &a,int b){a=a>=b?a-b:a+mod-b;}
inline int add(int a,int b){return a>=mod-b?a-mod+b:a+b;}
inline int red(int a,int b){return a>=b?a-b:a+mod-b;}
int ksm(int a,int b){
int res=1;
while(b>0){
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
int f[N],g[N],F[N],G[N],FG[N];
int jc[K],invj[K];
int n,m,p,b,k;
int C(int n,int m){
if(n<m||m<0)return 0;
return 1ll*jc[n]*invj[m]%mod*invj[n-m]%mod;
}
void prework(){
n=read(),m=read(),p=read(),b=read(),k=read();
p=1ll*p*ksm(b,mod-2)%mod;
for(int i=jc[0]=1;i<K;++i)jc[i]=1ll*jc[i-1]*i%mod;
invj[K-1]=ksm(jc[K-1],mod-2);
for(int i=K-2;~i;--i)invj[i]=1ll*invj[i+1]*(i+1)%mod;
for(int j=0;j<=m;++j)
g[j]=1ll*C(k,j)*ksm(p,j)%mod*ksm(red(1,p),k-j)%mod;
G[0]=g[0];
for(int j=1;j<=m;++j)
G[j]=add(G[j-1],g[j]);
}
signed main(){
prework();
F[m]=1,FG[m]=g[m]*F[m];
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j)
f[j]=1ll*g[m-j]*red(1ll*red(F[m],F[m-j])*G[j-1]%mod,FG[j-1])%mod;
for(int j=1;j<=m;++j)
F[j]=add(F[j-1],f[j]),
FG[j]=add(FG[j-1],1ll*g[j]*F[j]%mod);
}
printf("%d\n",F[m]);
return 0;
}
标签:prime,le,CF708E,int,题解,sum,Camp,复杂度,mod 来源: https://www.cnblogs.com/wyb-sen/p/16285792.html