cf 414B Mashmokh and ACM 动态规划

题目链接: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
", ans);

    return 0;
}
原文地址:https://www.cnblogs.com/dishu/p/4295089.html