题目链接: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#include #include #include #include #include #include #include #include <set> #include #include 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 ", ans);return 0; }