题目大意:满k叉树,每个顶点有k条边,边的权重为1~k,现求出从根节点出发,有多少条路径,使得总权值恰好为N,并且每条路径上至少有一条权值不少于d的边。
题目思路:dp[i][h],第一个参数从1-n,遍历权值为i的情况,h有两种情况,0和1,0表示权值为i的所有情况,1表示权值为i的时候路径中存在一个值大于d的情况。
状态转移方程:
//权值为i的处理所有情况
dp[i][0] = dp[i][0] + dp[i - j][0]
//处理权值为i且存在边大于等于d的情况
/* if (j >= d) dp[i][1] = dp[i][1] + dp[i - j ][0]
else dp[i][1] = dp[i][1] + dp[i - j ][1] */
即:dp[i][1] = dp[i][1] + dp[i - j][j<d]
所以结果为dp[n][1]
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
#include <stack>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-3
#define maxn 2000010
#define MOD 1000000007
int n,k,d;
int a[maxn],sum[maxn];
long long dp[110][2];
int main()
{
int t,C = 1;
while(scanf("%d%d%d",&n,&k,&d) != EOF)
{
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= min(k,i); j++)
{
if(j >= d)
dp[i][1] = (dp[i][1] + dp[i-j][0] + dp[i-j][1])%MOD;
else
{
dp[i][0] = (dp[i][0] + dp[i-j][0]) % MOD;
dp[i][1] = (dp[i][1] + dp[i-j][1]) % MOD;
}
}
}
printf("%I64d\n",dp[n][1]);
}
return 0;
}