http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4011
题意:t个样例 一个n 代表给你1 2 3 .。。。n的序列 一个m
问你组成长度为m的序列有多少个
关于长度为m 他是这样定义:【这里面有m个数】且每两个相邻的数 前者能整除后者 即后者%前者==0
比如n=5 m=3
有16个
111 222 333 444 555 可以发现这种类型有 n 个
112 113 114 115
122 133 144 155
124 224 244
然后发现怎么取 才能满足要求 :一开始认为这m个只能是一个数的 倍数才可以 2 4 6 6%4!=0
后来发现应该先取一个数a 然后以a为基准 找a的倍数b 然后定了b后 再找b的倍数c。。。。。凑够m个 即一种
暴力找 3秒也不够 m个for 每个for定一个数
每次都是看最后一个数 以它为基准 确定一个m长度也是从1个2个3个 m个这样确定的、
所以dp【i】【j】 填了i个数 且最后一个数(第i个数)是 j 的方案
预处理
先拿一个vector 保存1到2000各自 的因数
边界:dp【1】【】一个数肯定就是这 一个方案 所以初始化dp【1】【1到n】=1
for(i=2 到 m)开始填2个数3个。。。m个
for(填什么数 j=1到n)
如何转移 dp【i】【j】 = (dp【i】【j】和dp【i-1】【j】 前者的 j 是要能% 后者的 j == 0的,即前者的 j 是 后者的 j 的倍数,那就通过v【j】【】更新)
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
const int mod = 1e9 + 7;
int dp[2100][2100];
vector<int> v[2100];
int main() {
int t;
for (int i = 1; i <= 2000; ++i) {
dp[1][i] = 1;//边界条件
for (int j = 1; j <= i; ++j) {
if (i % j == 0) {
v[i].push_back(j); //i的所有因子
}
}
}
for (int i = 2; i <= 2000; ++i) {
for (int j = 1; j <= 2000; ++j) {
dp[i][j] = 0;
for (int k = 0; k < v[j].size(); ++k) {
dp[i][j] = (dp[i][j] + dp[i - 1][v[j][k]]) % mod;
}
}
}
scanf("%d", &t);
while (t--) {
int n, m;
scanf("%d%d", &n, &m);
long long ans = 0;
for (int i = 1; i <= n; ++i) {
ans = (ans + dp[m][i]) % mod;
}
printf ("%d\n", ans);
}
return 0;
}