【XSY3892】【hihocoder1147】时空阵(分层图dp)

\(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
*/
posted @ 2022-10-30 14:02  ez_lcw  阅读(20)  评论(0编辑  收藏  举报