ZOJ 4011 Happy Sequence 【dp】

版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/83181055

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4011

思路:

dp状态:dp 【数列长度】【数列最尾的那个数】

那么可以得出这个递推公式 : dp【当前数列长度】【数列最尾的数】 =   (dp【当前数列长度-1】【比当前数列尾数小或者等于,而且是当前尾数的倍数】的总和),从逻辑分析来看是合理的;因为数字可以重复取,比如m = 3 可以是 111,所以尾数可以等于当前的尾数;为什么dp公式这样写? 如果要整体考虑的话,会非常麻烦,但如果我们一个一个数的添加到数列里面,数列长度从1不断增加到 m,最后得出的就是我们要的结果;比如  n = 5, 我们要找出  m = 3, 尾数是 4的话,长度为2的数列有 1, 2;   2, 4 ; 我们这里暂时不考虑重复的(1,1; 2,2 类似这种) 那么只需要在1,2的后面加个 4; 2,4 后面加个 4,那么就得到 1,2,4; 2,4,4; 这样就有了2个符合题意的数列了;

对应数的倍数可以预先打表;然后要用的时候直接拿出来用就行了

//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<sstream>
#include<vector>
#include<string>
#include<set>

using namespace std;
//using namespace __gnu_pbds;

//------------------ 宏定义 --------------------------------

#define IOS ios::sync_with_stdio(false); cin.tie(0);
#define REP(i,n) for(int i=0;i<n;++i)

//------------------- 预备函数 ------------------------------
int read(){
    int r=0,f=1;char p=getchar();
    while(p>'9'||p<'0'){if(p=='-')f=-1;p=getchar();}
    while(p>='0'&&p<='9'){r=r*10+p-48;p=getchar();}return r*f;
}
int dcmp (double x, double y) {
    if (fabs(x-y) < 1e-6) return 0;
    if (x > y) return 1; return -1;
}

//------------------- 常量+声明 ------------------------------------------

//typedef tree<pair<long long,int>,null_type,less< pair<long long,int> >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<long long,long long> pll;
const int Maxn = 2e3+10;
const long long LINF = 1e18;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9+7;
const double PI = acos(-1.0);
const double esp = 1e-6;

//-------------------------------------------------------------------------

int dp[Maxn][Maxn];
vector <int> a[Maxn];

int main (void)
{   //  a存储的是小于或者等于j,能整除j的数
    for (int i = 1; i <= 2000; ++i) {
        for (int j = i; j <= 2000; j+=i) a[j].push_back (i);
    }
    int t, n ,m;
    scanf ("%d", &t);
    while (t--) {
        scanf ("%d%d", &n, &m);
        memset (dp, 0, sizeof (dp));
        dp[0][1] = 1;
        int ans = 0;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                int len = a[j].size();
                for (int k = 0; k < len; ++k) {
                    dp[i][j] = (dp[i][j] + dp[i-1][a[j][k]]) % Mod;
                }
            if (i == m) ans = (ans + dp[i][j]) % Mod;
            }
        }
        printf ("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/83181055