您的位置:首页 > 其它

HDU 6148 数位dp

2017-08-20 22:18 260 查看

题意:

题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 数位dp