其他分享
首页 > 其他分享> > CF848D Shake It!

CF848D Shake It!

作者:互联网

Link
我们考虑dp,设\(f_{i,j}\)表示进行\(i\)次操作后Mincut为\(j\)的方案数。
转移与背包类似,考虑枚举成对的\(f\)进行转移,对于\(f_{i,j}\),我们枚举\(f_{a,b},f_{c,d}\),使得\(f_{i,j}\)的\(s\)与\(f_{a,b}\)的\(s\)重合,\(f_{a,b}\)的\(t\)与\(f_{c,d}\)的\(s\)重合,\(f_{c,d}\)的\(t\)与\(f_{i,j}\)的\(t\)重合,然后再枚举添加\(x\)对\(f_{a,b}-f_{c,d}\)。
这样就有:\(f_{i,j}{f_{a,b}f_{c,d}+x-1\choose x}\rightarrow f_{i+x(a+c+1),j+x\min(b,d)}\)。
这样做的时间复杂度是\(O(n^6\log n)\)(枚举\(x\)的复杂度为调和级数),无法接受。
考虑优化,设\(g_{i,j}=\sum\limits[a+c+1=i\wedge\min(b,d)=j]f_{a,b}f_{c,d}\),这样我们就可以先求出\(g_{i,j}\)再更新\(f_{i,j}\),时间复杂度为\(O(n^4\log n)\),非常优秀。

#include<cstdio>
#include<cstring>
const int N=57,P=1000000007;
void mod(int&x){x-=P,x+=x>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int f[N][N],g[N][N],t[N][N],inv[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m),inv[0]=inv[1]=f[0][1]=1;
    for(int i=2;i<=n;++i) inv[i]=mul(inv[P%i],P-P/i);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=i+1;++j)
    {
        for(int k=0;k<=i-1;++k)
        {
        for(int l=j;l<=k+1;++l) mod(g[i][j]+=mul(f[k][l],f[i-1-k][j]));
        for(int l=j+1;l<=i-k;++l) mod(g[i][j]+=mul(f[k][j],f[i-1-k][l]));
        }
        memset(t,0,sizeof t);
        for(int k=0;k<=n;++k) for(int p=1;p<=k+1;++p) for(int q=1,s=1;k+q*i<=n;++q) s=mul(mul(s,g[i][j]+q-1),inv[q]),mod(t[k+q*i][p+q*j]+=mul(f[k][p],s));
        for(int k=0;k<=n;++k) for(int l=1;l<=k+1;++l) mod(f[k][l]+=t[k][l]);
    }
    printf("%d",f[n][m]);
}

标签:log,int,CF848D,inv,重合,枚举,Shake,复杂度
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/12252235.html