HDU5779 Tower Defence

dp[i][j][k] 已选i个人 选到第j层 第j层有k个人

讨论相邻层  上一层选了l人 那么共有 两层之间的方案数 以及这一层自己的方案数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9+7;
ll Pow[3605];
ll dp[65][65][65];
ll C[65][65];
int N,K;
void debug(){
	for(int i = 1; i <= N; ++i)
		for(int j = 1; j <= 1; ++j)
			for(int k = 1; k <= N; ++k)
				printf("dp[%d][%d][%d]=%lld  ",i,j,k,dp[i][j][k]);
	printf("\n");
}
ll PPow(ll x,int y){
	if(x==-1) x += MOD;
	ll ans = 1;
	while(y){
		if(y&1) ans = ans*x% MOD;
		y >>= 1; x = x*x %MOD;
	}
	return ans;
}
int Judge(int x,int y,int z){
	int tt = x-z;
	if(y == 1) return tt==0;
	else if(tt >= y-1) return 1;
	else return 0;
}
int main(){
	int T;
	Pow[0]=1;
	C[0][0]=1;
	for(int i = 1; i < 65; ++i)
		for(int j = 0; j <= i; ++j)
			if(j) C[i][j] = (C[i-1][j]+C[i-1][j-1]) % MOD;
			else  C[i][j] = 1;
	for(int i = 1; i < 3605; ++i) Pow[i] = Pow[i-1]*2%MOD;
	scanf("%d",&T);
	while(T--){
		memset(dp,0,sizeof(dp));
		scanf("%d %d",&N,&K);	
		N--;	
		for(int j = 1; j < K; ++j)
			for(int i = 1; i <= N; ++i){
				if(j==1) { dp[i][j][i]=C[N][i]*Pow[i*(i-1)/2] % MOD; continue; }
				for(int k = 1; k <= i; ++k)
					for(int l = 1; l <= i; ++l){
				//	printf("%lld ",dp[i][j][k]);
						if(Judge(i,j,k) &&  Judge(i-k,j-1,l) ) dp[i][j][k] = (dp[i][j][k] + dp[i-k][j-1][l] * C[N-i+k][k] % MOD 
								* PPow(Pow[l]-1,k) %MOD * Pow[k*(k-1)/2] %MOD ) % MOD;
				//		printf("%d %d %d %d: %lld %lld %lld\n",i,j,k,l,dp[i][j][k],C[N-i+k][k],PPow(Pow[l]-1,k) ) ;
					}
			}
	//	debug();

		ll sum = Pow[N*(N-1)/2];
		for(int i = 1; i <= N; ++i)
			for(int j = 1; j <= K; ++j)
				for(int k = 1; k <= N; ++k){
					
				//	if(sum) printf("%d %d %d\n",i,j,k);
					sum = (sum + dp[i][j][k]*Pow[(N-i)*(N-i-1)/2]) % MOD;
				}
		printf("%lld\n",sum);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值