我们发现,操作若干次后形成的世界,实际是在原来的一对点(源汇集合)的基础上,加入了许多对(pair)小世界,每一对小世界由中间的连接点和他连接的两个小世界组成,每对之间互相独立,无序,于是我们发现可以把问题不断这样划分直到一个世界就只有源汇和他们之间的边
我们用f[i][j]表示i次操作后,最小割为j的世界有多少个,他可以由某个世界添加一对或者多对规模相同的小世界得到,于是有
f[i][j]=f[p][q]+MultiCombination(pair<(a,b),(c,d)>,t)
(p+t∗(a+c+1)=i,q+t∗min(b,d)=j)
MultiCombination(n,m)=Cmn+m−1
即可重组合
后面那个东西独立,表示i次操作,最小割为j的一对世界的方案数,用g[i][j]记录
然后我们考虑去重,因为pair之间是无序的,所以会产生重复,那么我们只要使他变得有序就行了
又因为g[i][j]是由规模比他小的f[p][q] dp来的,所以我们将一个世界的所有对小世界按照操作次数为第一关键字,最小割为第二关键字排序,按照这个顺序,从小到大,用f更新g[i][j],用g[i][j]更新所有f
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 60;
const ll Mod = 1e9+7;
ll pw(ll x,int k)
{
ll re=1ll;
for(;k;k>>=1,x=x*x%Mod)
if(k&1) (re*=x)%=Mod;
return re;
}
int n,m;
ll inv[maxn];
ll f[maxn][maxn],g[maxn][maxn],h[maxn][maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<maxn;i++) inv[i]=pw(i,Mod-2);
f[0][1]=1ll;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
for(int a=0;a<=i-1;a++)
{
int c=i-1-a;
for(int b=j;b<=a+1;b++) g[i][j]+=f[a][b]*f[c][j]%Mod;
for(int d=j+1;d<=c+1;d++) g[i][j]+=f[a][j]*f[c][d]%Mod;
}
g[i][j]%=Mod;
for(int p=0;p<=n-i;p++)
{
for(int q=1;q<=p+1;q++)
{
ll tmp=f[p][q];
if(!tmp) continue;
for(int t=1;p+i*t<=n;t++)
{
tmp=tmp*(g[i][j]+t-1)%Mod*inv[t]%Mod;
h[p+i*t][q+j*t]+=tmp;
}
}
}
for(int p=0;p<=n;p++) for(int q=0;q<=p+1;q++) (f[p][q]+=h[p][q]%Mod)%=Mod,h[p][q]=0;
}
}
printf("%I64d\n",f[n][m]%Mod);
return 0;
}