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;
    }
    
  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/Point-King/p/14570506.html
Copyright © 2011-2022 走看看