其他分享
首页 > 其他分享> > CF708E Student's Camp 题解

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] \]

考虑多算了什么东西,多算了

所以枚举一下 \(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