1. 程式人生 > >ZOJ - 4011 Happy Sequence【dp】 2018 ZOJ march月賽

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;
}