「专题训练」k-Tree(CodeForces Round #247 Div.2 C)

题意与分析(Codeforces-431C)

题意是这样的:给出K-Tree——一个无限增长的树,它的每个结点都恰有\(K\)个孩子,每个节点到它\(K\)个孩子的\(K\)条边的权重各为\(1,2,...,K\),问现有多少条路径,使从根节点出发到某个结点所经过的边权重之和恰为n,且经过的边至少有一条权重不小于\(d\)
我们来考虑一下阶段:一层一层的走下去——这个是显然的。而状态是什么?影响我们答案(路径条数)的只有一个,权重的和,它是由我们底下的若干个孩子所走的权重和的情况的和构成的。从某个节点走到某个节点改变了什么?当我走了一条边i,我就还剩\(n-i\)的权重需要走了。而我有\(k\)个边,因此对于一个K-Tree的某个点(每个点是等价的,所以决定性因素只能是和),如果它还剩\(n\)的权重和没有走,那么它的状态转移方程就是\(dp[n-1]+dp[n-2]+...+dp[n-k]=dp[n]\)。这样就能求出没有限制条件下的路径个数。
然后考虑一下限制条件。不小于\(d\),很自然地会觉得有点困难去实现。于是想到正难则反,我们求出所有边权重小于d的情况就行了——也就是\(k=d-1\)。而同样的,不改变的是预先的权重和\(n\),因此再次运用上面的状态转移方程,然后把\(k\)代入为\(d-1\)即可。二者最后相减即可。

代码

注意减法操作时候的取模。

#include <bits/stdc++.h>
using namespace std;

const long long mod=1e9+7;
long long dpa[105], dpb[105];
int main()
{
	int n,k,d; cin>>n>>k>>d;
	dpa[0]=dpb[0]=1;
	for(int i=1;i<=n;++i)
	{
		for(int j=1; j<=k && i-j>=0; ++j)
		{
			dpa[i]=(dpa[i]+dpa[i-j])%mod;
		}
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1; j<=d-1 && i-j>=0; ++j)
		{
			dpb[i]=(dpb[i]+dpb[i-j])%mod;
		}
	}
	cout<<(dpa[n]-dpb[n]+mod)%mod<<endl;
	return 0;
}
posted @ 2018-12-01 11:03  ISoLT  阅读(252)  评论(0编辑  收藏  举报