ZOJ - 4011 Happy Sequence【dp】 2018 ZOJ march月賽
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;
}