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-1choose x}
ightarrow f_{i+x(a+c+1),j+xmin(b,d)})。
这样做的时间复杂度是(O(n^6log n))(枚举(x)的复杂度为调和级数),无法接受。
考虑优化,设(g_{i,j}=sumlimits[a+c+1=iwedgemin(b,d)=j]f_{a,b}f_{c,d}),这样我们就可以先求出(g_{i,j})再更新(f_{i,j}),时间复杂度为(O(n^4log 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]);
}