zoukankan      html  css  js  c++  java
  • CF708E Student's Camp

    题解

    你考虑暴力怎么做。

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

    [f_{i,l,r}= ext{cal}(l,r)cdotsum_{[l',r']cap[l,r] eempty}f_{i-1,l',r'} ]

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

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

    [f_{i,l,r}= ext{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}= ext{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}= ext{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} ext{cal}(l,r)cdot(F(i-1)-L(i-1,l)-L(i-1,m-r+1))\ =sum_{lle j} ext{cal}(l,j)cdot(F(i-1)-L(i-1,l)-L(i-1,m-j+1))\ ]

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

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

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

    然后继续推

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

    我不行了。


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

    [ ext{cal}(l,r)=func(l-1)cdot func(m-r)\ L'(i,j)=sum_{lle j} ext{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))cdotsum_{lle j}func(l-1)-sum_{lle j}func(l-1)cdot L(i-1,l))) ]

    然后求一下 (sum_{lle j}func(l-1))(sum_{lle 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
    ",f[m+1]),0;
    }
    
  • 相关阅读:
    快速幂精讲+代码实现
    基数排序
    Java学习-常见排序算法
    C++中不清楚的函数用法汇总
    C++中的堆及常见题目汇总
    django+nginx+uwsgi+vue部署服务器
    nginx+WSGI+uwisgi+uWISI详解及nginx/uwisgi/django交互流程
    C++中的哈希表及常见题目汇总
    C++中的二叉树及相关题目汇总
    C++中的队列及常见题目汇总
  • 原文地址:https://www.cnblogs.com/Point-King/p/14570506.html
Copyright © 2011-2022 走看看