题目链接:http://codeforces.com/problemset/problem/414/B
dp[i][j]表示长度为i、最后一个数字为j的合法序列总数
dp[1][1...2000]都是1
后面用dp[i-1][j] 去更新 dp[i][j*t] (1 <= j*t <= 2000) 即用因子去更新它的倍数
表面上看是2000^3的复杂度会爆 其实不用算那么多次
最外层循环是2000
分析第二层和第三层 需要算 2000/1 + 2000/2 + 2000/3 + 2000/4 + ... + 2000/2000 次
即2000 * (1/1 + 1/2 + 1/3 + ... + 1/2000)
后面的括号是一个【调和级数】 利用高等数学知识可知 它是有上限的 为自然对数e
所以本算法的时间复杂度实际上仅为 e*2000*2000
绰绰有余
因为下标从1开始计数
然后一开始fill的时候没注意看wa了几炮T^T
#include <cstdio> #include <cstdlib> #include <ctime> #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <stack> #include <set> #include <queue> #include <vector> using namespace std; const int maxn = 2010; const int M = 1000000007; int dp[maxn][maxn]; int main() { //freopen("in.txt", "r", stdin); int n, k; scanf("%d%d", &n, &k); fill(dp[1] + 1, dp[1] + 2001, 1); for(int i = 2; i <= k; i++) { for(int j = 1; j <= 2000; j++) { for(int t = 1; j*t <= 2000; t++) { dp[i][j*t] = (dp[i][j*t] + dp[i-1][j]) % M; } } } int ans = 0; for(int i = 1; i <= n; i++) ans = (ans + dp[k][i]) % M; printf("%d\n", ans); return 0; }
时间: 2024-11-20 19:19:41