ZOJ Monthly, March 2018 - H 动态规划

ZOJ Monthly, March 2018 - H 动态规划


题目描述

对于一个长度为k的数列,若每一个元素都能整除后面一个元素,则称之为快乐数列。现在给出n和m,找出n以内的所有长度为m的快乐数列,输出数量。

Sample Input

1 3
2

Sample output

5

问题分析

设dp[i][j]为长度为i,结尾数字为j的数列。那么容易得到状态转移公式$dp[i][j] = \sum dp[i-1][k]$,其中k是能整除j的所有正整数。那么最后答案即为$\sum dp[m]i.先预处理一下小于2000的所有数的因子

代码实现

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
const int modd = 1e9 + 7;
const int maxn = 2000 + 10;
int dp[maxn][maxn];  //长度为n,结尾数字为m
vector<int> num[maxn];

void init()
{
  for(int i=1;i<=2000;i++)
    for(int j=i;j>=1;j--)
      if((i%j) == 0)  num[i].push_back(j);  //预处理因子
  for(int i=1;i<=2000;i++)  dp[1][i] = 1;
  for(int i=2;i<=2000;i++)
    for(int j=1;j<=2000;j++)
      for(int k=0;k<num[j].size();k++)
        dp[i][j] = (dp[i][j] + dp[i-1][num[j][k]]) % modd;
}

int main()
{
  init();
  int kase,n,m;
  LL ans;
  cin >> kase;
  while(kase--)
  {
    ans = 0;
    cin >> n >> m;
    for(int i=1;i<=n;i++)
    {
      ans += dp[m][i];
    }
    cout << ans % modd << endl;
  }
}
... ... ...