设 \(dp(i,t,l)\) 表示已经定好前 \(i\) 层,共有 \(t\) 个节点,其中第 \(i\) 层有 \(l\) 个节点。
直接转移即可,注意一些细节:
-
第 \(1\) 层只有 \(1\) 号节点。
-
同层之间可以乱连,相邻层之间可以乱连,跨层之间不能连。
-
需要钦定 \(n\) 号点在第 \(m+1\) 层。
#include<bits/stdc++.h>
#define N 110
#define ll long long
#define mod 1000000007
using namespace std;
int n,k;
ll pow2[N*N],fac[N],inv[N];
ll f[N][N][N];
void add(ll &x,ll y)
{
if((x+=y)>=mod) x-=mod;
}
ll poww(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
pow2[0]=fac[0]=1;
for(int i=1;i<=n*n;i++)
pow2[i]=(pow2[i-1]<<1ll)%mod;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
inv[n]=poww(fac[n],mod-2);
for(int i=n-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(int n,int m)
{
if(n<m) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
// freopen("my_f.txt","w",stdout);
scanf("%d%d",&n,&k);
init();
f[1][1][1]=1;
ll ans=0;
for(int i=2;i<=k+1;i++)
{
for(int t=i;t<=n-(k+1-i);t++)
{
for(int l=1;l<=t-(i-1);l++)
{
for(int p=1;p<=t-l-(i-2);p++)
add(f[i][t][l],f[i-1][t-l][p]*poww(pow2[p]-1,l)%mod);
f[i][t][l]=f[i][t][l]*pow2[C(l,2)]%mod;
if(i<=k) f[i][t][l]=f[i][t][l]*C(n-(t-l)-1,l)%mod;//这里n-(t-l)再减去1的原因是需要钦定n在第m+1层
else
{
f[i][t][l]=f[i][t][l]*C(n-(t-l)-1,l-1)%mod;
add(ans,f[i][t][l]*pow2[l*(n-t)]%mod*pow2[C(n-t,2)]%mod);
}
}
}
}
printf("%lld\n",ans);
return 0;
}
/*
4 3
*/
/*
100 50
*/
标签:XSY3892,hihocoder1147,int,ll,ans,define,inv,dp,mod
From: https://www.cnblogs.com/ez-lcw/p/16841163.html