【BHOJ DH的满k叉树】DP | 动归 | E

DH的满k叉树

URL: DH的满k叉树

时间限制: 1000 ms 内存限制: 204800 kb

总通过人数: 80 总提交人数: 85

题目描述

有一颗无穷深的满k叉树,且每一个节点与它的子节点相连的边的权值分别为1,2,…,k,DH现在想知道在这棵树上有多少条从根出发不重复经过边的路径满足经过的边权值之和为n而且至少经过一条权值不小于d的边

输入

多组输入数据,对于每一组输入数据,为一行,包括三个整数 n, k, d ( 1≤ n,k ≤100, 1≤ d ≤ k ) 

输出

对于每一组数据,输出一行,为该组数据答案对1000000007(1e9+7)取模的结果

输入样例

1 1 1

输出样例

1

分析

算是比较基础的 dp 了:

  1. 【定义】: dp[i][j] 表示 路径和为i、只选用每一层的[1, j]边 的 方案总数

  2. 初始化dp[0][...] = 0(自然方案数 == 1)

  3. 【递推顺序】:外层循环第一维[1, MAX](从1开始增加路径和),内层循环第二维[1, MAX](逐渐扩大选择边的范围)

  4. 【状态转移方程】:dp[i][j] = sum { dp[i-k][j] } (k<=i,否则路径和不可能为i;同时k<=j,否则超出可选范围)

  5. 【答案】:dp[n][k] - dp[n][d-1](即总方案数 - 只选比d小的边的方案数)(做了减法,还要记得 +MODD 再 %MODD)

AC代码 

#include <stdio.h>
#define sc(x) {register char _c=getchar(),_v=1;for(x=0;_c<48||_c>57;_c=getchar())if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=getchar());x*=_v;}
#define se(x) {register char _c=getchar(),_v=1;for(x=0;_c<48||_c>57;_c=getchar())if(_c==45)_v=-1;else if(_c==-1)return 0;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=getchar());x*=_v;}
#define PC putchar
void PRT(const int a){if(a>=10)PRT(a/10);putchar(a%10+48);}

#define MN 100
#define MODD 1000000007

int dp[MN+3][MN+3];

void table(void)
{
	int i, j, k;
	for (i=1; i<=MN; i++)
		dp[0][i] = 1;

	for (i=1; i<=MN; i++)
	{
		for (j=1; j<=MN; j++)
		{
			for (k=1; k<=i && k<=j; k++)
			{
				dp[i][j] += dp[i-k][j];
				dp[i][j] %= MODD;
			}
		}
	}
}

int main()
{
	table();
	int n, k, d;
	while (1)
	{
		se(n)sc(k)sc(d)
		PRT((dp[n][k] - dp[n][d-1] + MODD) % MODD), PC(10);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_42102584/article/details/83218842
今日推荐