Codeforces 431C. k-Tree

Quite recently a creative student Lesha had a lecture on trees. After the lecture Lesha was inspired and came up with the tree of his own which he called a k-tree.

k-tree is an infinite rooted tree where:

  • each vertex has exactly k children;
  • each edge has some weight;
  • if we look at the edges that goes from some vertex to its children (exactly k edges), then their weights will equal 1,?2,?3,?...,?k.

The picture below shows a part of a 3-tree.

As soon as Dima, a good friend of Lesha, found out about the tree, he immediately wondered: "How many paths of total weight n (the sum of all weights of the edges in the path) are there, starting from the root of a k-tree and also containing at least one edge of weight at least d?".

Help Dima find an answer to his question. As the number of ways can be rather large, print it modulo 1000000007 (10^9?+?7).

Input

A single line contains three space-separated integers: nk and d (1?≤?n,?k?≤?100; 1?≤?d?≤?k).

Output

Print a single integer — the answer to the problem modulo 1000000007 (10^9?+?7).

动归题,列出式子

设dp[i][0]是长度为i且其中没有大于等于d的边的方案数,dp[i][1]是长度为i且其中有至少一条大于等于d的边的方案数,则

i < d时

dp[i][0] = Σdp[i-a][0] (a∈[1,i]); dp[i][1] = 0

i >= d

dp[i][0] = Σdp[a][0] (a∈[i-d+1,i-1])

dp[i][1] = Σdp[a][0] (a∈[max(0,i-k),i-d]) + Σdp[i-a][1] (a∈[max(0,i-k),i-1])

本题就是要求dp[n][1]

然后注意下边界的初始化即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include <string>
#include <sstream>
#include <map>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <stack>
#include <queue>
#include <set>
using namespace std;
typedef long long LL;
#define MOD 1000000007
LL dp[105][2];
LL n,k,d;
int main(){
  // freopen("test.in","r",stdin);
  cin >> n >> k >> d;
  memset(dp,0,sizeof(dp));
  dp[1][0] = 1; dp[0][0] = 1;
  if (d == 1){
    dp[1][1] = 1; dp[1][0] = 0;
  }
  for (int i=2;i<=n;i++){
    if (i < d){ // dp[i][1] length = n weight >= d
      dp[i][1] = 0;
      // dp[i][0] = Σdp[i-a][0] (a∈[1,i]);
      for (int j=1;j<=i;j++){
        dp[i][0] += dp[i-j][0];
        dp[i][0] %= MOD;
      }
    }
    else {
      // dp[i][0] = Σdp[a][0] (a∈[i-d+1,i-1])
      for (int j=i-d+1;j<=i-1;j++){
        dp[i][0] += dp[j][0];
        dp[i][0] %= MOD;
      }
      // dp[i][1] = Σdp[a][0] (a∈[max(0,i-k),i-d]) + Σdp[i-a][1] (a∈[max(0,i-k),i-1])
      LL now;
      if (i-k>0){
        now = i -k;
      }
      else {
        now = 0;
      }
      for (int j=now;j<=i-1;j++){
        dp[i][1] += dp[j][1];
        dp[i][1] %= MOD;
      }
      for (int j=now;j<=i-d;j++){
        dp[i][1] += dp[j][0];
        dp[i][1] %= MOD;
      }
    }
  }
  // for (int i=1;i<=n;i++){
  //   cout << dp[i][1] << " " << dp[i][0] << endl;
  // }
  cout << dp[n][1] % MOD;
  return 0;
}

时间: 2024-10-29 12:40:07

Codeforces 431C. k-Tree的相关文章

Problem - D - Codeforces Fix a Tree

Problem - D - Codeforces  Fix a Tree 看完第一名的代码,顿然醒悟... 我可以把所有单独的点全部当成线,那么只有线和环. 如果全是线的话,直接线的条数-1,便是操作数. 如果有环和线,环被打开的同时,接入到线上.那就是线和环的总数-1. 如果只有环的话,把所有的环打开,互相接入,共需n次操作. #include <cstdio> #include <algorithm> using namespace std; const int maxn =

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

codeforces 570 D. Tree Requests 树状数组+dfs搜索序

链接:http://codeforces.com/problemset/problem/570/D D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a low

CodeForces 383C Propagating tree

Propagating tree Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ID: 383C64-bit integer IO format: %I64d      Java class name: (Any) Iahub likes trees very much. Recently he discovered an interesting tree

codeforces 219a k重复字符串。

背景:周赛d题,当时没读题,怎么知道其实有点水的,也是自己codeforces第一题吧,仰慕torist神牛.! #include<stdio.h> #include<string.h> int a[26],n=0; char b[1009]; bool ok(void); bool ok(void) { for(int j=0;j<26;j++) if(a[j]%n!=0) return false; return true; } int main(void) { whil

Codeforces 343D Water Tree(DFS序+线段树+技巧)

题目链接:http://codeforces.com/problemset/problem/343/D 题目: Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water. The vertices of the tree are numbered f

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

codeforces 1041 E. Tree Reconstruction 和度数有关的构造树

CF 1041E:http://codeforces.com/contest/1041/problem/E 题意: 告诉你一个树的节点个数,显然有n-1条边.已知去掉一条边后,两个集合中最大的节点值.问原来的树形状是怎么样的,构造不出来就输出NO. 思路: 这里说的“度数”可能有点不恰当.指以这个点引出一条链的长度,链上点的值小于这个点. 我想着这应该是可以作为一条链的,但是一直没有想到向节点度数上去想.首先,输入的一对值中,有一个一定是等于n的,那另一个值我们给它度数++.我们把度数为0的点从

CodeForces - 1118 F2 Tree Cutting

题目传送门 题解: 先注意到一定存在k种颜色,切成k个块, 然后要求每个块内的颜色都一样,所以可以发现同一种颜色一定在同一个块内,故任意2个相同颜色的最短路劲上的点的颜色都是该颜色. 我们可以先把任意相同颜色点对的路径上的点的颜色都染成这个颜色. 如果发现存在一个点是已经有颜色的话,那么答案一定为0. 至于怎么颜色, 我们可以暴力往上跑,然后压缩路径,和并查集一样的道理,路过的点都染色且压缩. 这样就完成了第一部分的处理,接下来就是树DP了. 定义dp[ u ][ 0 ] 的含义是 以u为根的子