CF708E Student's Camp

题解

你考虑暴力怎么做。

\(f_{i,l,r}\) 表示到达第 \(i\) 行,左右边界为 \(l\)\(r\) 时联通的概率,那么状态转移式是:

\[f_{i,l,r}=\text{cal}(l,r)\cdot\sum_{[l',r']\cap[l,r]\ne\empty}f_{i-1,l',r'} \]

然后这个东西直接做必然是 \(O(nm^2)\) 的,非常不优美,所以我们要考虑优化。

我们观察这个转移式的求和,发现其可以被拆成三个求和式的互相加减,即

\[f_{i,l,r}=\text{cal}(l,r)\cdot(\sum f_{i-1,l',r'}-\sum_{r'<l}f_{i-1,l',r'}-\sum_{l'>r}f_{i-1,l',r'}) \]

我们定义

\[F(i)=\sum f_{i,l,r}\\ L(i,j)=\sum_{r<j}f_{i,l,r}\\ R(i,j)=\sum_{l>j}f_{i,l,r} \]

\[f_{i,l,r}=\text{cal}(l,r)\cdot(F(i-1)-L(i-1,l)-R(i-1,r)) \]

可以比较轻易的得到, \(L(i,j)=R(i,m-j+1)\) ,所以式子又变成了

\[f_{i,l,r}=\text{cal}(l,r)\cdot(F(i-1)-L(i-1,l)-L(i-1,m-r+1)) \]

那我们最后的答案就是 \(F(n)\)

考虑我们定义的这几个东西怎么转移。

我们再定义

\[L'(i,j)=\sum_{r=j}f_{i,l,r} \]

那么显然

\[L(i,j)=\sum_{k<j}L'(i,k)\\ F(i)=\sum L'(i,k) \]

我们再考虑如何求我们再定义的这个东西,我们将 \(f\) 的转移式子带进去。

\[L'(i,j)=\sum_{r=j}f_{i,l,r}\\ =\sum_{r=j}\text{cal}(l,r)\cdot(F(i-1)-L(i-1,l)-L(i-1,m-r+1))\\ =\sum_{l\le j}\text{cal}(l,j)\cdot(F(i-1)-L(i-1,l)-L(i-1,m-j+1))\\ \]

发现不是很好搞了,我们考虑再定义一个前缀和

\[\text{cal}'(i,j)=\sum_{l=i}^j\text{cal}(l,j) \]

这个东西可以在一开始预处理好,复杂度是 \(O(m^2)\) 的。

然后继续推

\[L'(i,j)=(F(i-1)-L(i-1,m-j+1))\cdot\text{cal}'(1,j)-\sum_{l\le j}\text{cal}(l,j)\cdot L(i-1.l)\\ =(F(i-1)-L(i-1,m-j+1))\cdot\text{cal}'(1,j)-\sum_{l\le j}\text{cal}(l,j)\cdot\sum_{k<l}L'(i-1,k)\\ =(F(i-1)-L(i-1,m-j+1))\cdot\text{cal}'(1,j)-\sum_{k<j}L'(i-1,k)\cdot\text{cal}'(k+1,j)\\ \]

我不行了。


高啊,应该把 \(\text{cal}\) 拆开来搞。

\[\text{cal}(l,r)=func(l-1)\cdot func(m-r)\\ L'(i,j)=\sum_{l\le j}\text{cal}(l,j)\cdot(F(i-1)-L(i-1,l)-L(i-1,m-j+1))\\ =func(m-j)((F(i-1)-L(i-1,m-j+1))\cdot\sum_{l\le j}func(l-1)-\sum_{l\le j}func(l-1)\cdot L(i-1,l))) \]

然后求一下 \(\sum_{l\le j}func(l-1)\)\(\sum_{l\le j}func(l-1)\cdot L(i-1,l)\) 即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1505,T=1e5+5;
const int MOD=1e9+7;
int n,m,a,_a,b,t;
int frac[T],ifrac[T];
int ksm(int x,int k){
	int res=1;
	for(;k;k>>=1,x=x*x%MOD)
	if(k&1) res=res*x%MOD;
	return res;
}
int C(int n,int m){
	if(n<m||n<0||m<0) return 0;
	return frac[n]*ifrac[m]%MOD*ifrac[n-m]%MOD;
}
int f[N],g[N],h[N],func[T],sum[N];
signed main(){
	cin>>n>>m>>a>>b>>t;
	a=a*ksm(b,MOD-2)%MOD,_a=(1-a+MOD)%MOD;
	frac[0]=1;
	for(int i=1;i<=t;++i) frac[i]=frac[i-1]*i%MOD;
	ifrac[t]=ksm(frac[t],MOD-2);
	for(int i=t;i>=1;--i) ifrac[i-1]=ifrac[i]*i%MOD;
	for(int i=0;i<=t;++i) func[i]=C(t,i)*ksm(a,i)%MOD*ksm(_a,t-i)%MOD;
	for(int i=1;i<=m;++i) sum[i]=(sum[i-1]+func[i-1])%MOD;
	g[m]=1;
	for(int i=1;i<=m+1;++i) f[i]=(f[i-1]+g[i-1])%MOD;
	for(int i=1;i<=m;++i) h[i]=(h[i-1]+f[i]*func[i-1])%MOD;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j) g[j]=((f[m+1]-f[m-j+1]+MOD)*sum[j]%MOD-h[j]+MOD)%MOD*func[m-j]%MOD;
		for(int j=1;j<=m+1;++j) f[j]=(f[j-1]+g[j-1])%MOD;
		for(int j=1;j<=m;++j) h[j]=(h[j-1]+f[j]*func[j-1])%MOD;
	}
	return printf("%lld\n",f[m+1]),0;
}
posted @ 2021-03-23 17:05  Point_King  阅读(32)  评论(0)    收藏  举报