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


 


 

猜你喜欢

转载自blog.csdn.net/liangnimahanwei/article/details/83180577
ZOJ