HDU 6148 数位dp

来源:互联网 发布:js删除对象元素 编辑:程序博客网 时间:2024/06/10 18:23

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6148
中文题。


思路:

dp[pos][pre][flag]表示当前dp到第pos位且前一个数位上的数字是pre方案数,flag为0表示当前处于递减阶段,flag=1表示递增阶段。dp很简单,但有两点需要注意,一个是前导零的处理,另一个是对于山谷转折点的处理,因为数字可以满足相邻的相同,所以在某一位决定转折(从递减到递增)的时候需要在下一位从pre+1开始枚举,因为如果从pre开始枚举,那与这一位不做转折点的情况一样了,会产生重复。


代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL mod = 1e9 + 7;LL dp[105][15][2][2];int a[105];LL dfs(int pos, int pre, int flag, bool limit, bool zero) {    if (pos == -1) {        if (zero) return 0;        return 1;    }    if (!limit && dp[pos][pre][flag][zero] != -1) return dp[pos][pre][flag][zero];    LL res = 0;    int up = limit ? a[pos] : 9;    if (zero) {        for (int i = 0; i <= up; i++)            res = (res + dfs(pos - 1, i, 0, limit && a[pos] == i, i == 0)) % mod;    }    else {        if (flag == 0) {            for (int i = 0; i <= up && i <= pre; i++)                res = (res + dfs(pos - 1, i, 0, limit && a[pos] == i, 0)) % mod;            for (int i = pre + 1; i <= up; i++)                res = (res + dfs(pos - 1, i, 1, limit && a[pos] == i, 0)) % mod;        }        else {            for (int i = pre; i <= up; i++)                res = (res + dfs(pos - 1, i, 1, limit && a[pos] == i, 0)) % mod;        }    }    if (!limit) dp[pos][pre][flag][zero] = res;    return res;}char str[105];int main() {    memset(dp, -1, sizeof dp);    int T;    scanf("%d", &T);    while (T--) {        scanf("%s", str);        int len = strlen(str);        for (int i = 0; i < len; i++)            a[i] = str[len - i - 1] - '0';        LL ans = dfs(len - 1, 0, 0, 1, 1);        printf("%I64d\n", ans);    }    return 0;}
原创粉丝点击