HDU6148 Valley Numer {DP}【数位DP】
题解
查找区间 [ 0 , n ] [0, n] [0,n]内有多少个数字上没有峰值的数字。注意 12221 12221 12221也算有峰值。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define lowbit(x) ((x) & -(x));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e5 + 10, NN = 1e3 + 10, INF = 0x3f3f3f3f, LEN = 110;
const ll MOD = 1e9 + 7;
const ull seed = 31;
ll digit[LEN];
ll dp[LEN][10][3]; //三维下标为0表示不确定前面的状态,1表示递减,2表示递增
ll dfs(ll len, bool ismax, ll isup, ll last, bool lead_zero) {
// lead_zero表示是否处理到了可以处理的数字,意思就是是否已经抛弃了前导零
ll ans = 0;
if (!len)
return lead_zero ? 1LL : 0LL;
//若已经抛弃前导零找到可以处理的数字则输出1
if (!ismax && dp[len][last][isup] != -1)
return dp[len][last][isup];
ll maxx = ismax ? digit[len] : 9LL;
for (ll i = 0; i <= maxx; i++) {
if (isup == 2 && i < last)
continue;
//若isup已经为2就是之前已经出现递增,若i<last则在递增后又出现了递减,不允许出现这种情况,跳过
else if (!lead_zero && i == 0)
ans =
(ans + dfs(len - 1, ismax && i == maxx, isup, i, false)) % MOD;
//若还在前导零的范围内并且i还是0,则lead_zero继续为false
else if (!lead_zero)
ans = (ans + dfs(len - 1, ismax && i == maxx, isup, i, true)) % MOD;
//若找到了可以处理的数字并且这个数字之前是前导零
else if (i == last)
ans = (ans + dfs(len - 1, ismax && i == maxx, isup, i, true)) % MOD;
//若i与前一个相同
else
ans = (ans + dfs(len - 1, ismax && i == maxx, i > last ? 2 : 1, i,
true)) %
MOD;
//若不同
}
if (!ismax)
dp[len][last][isup] = ans;
return ans;
}
ll solve(char str[]) {
ll len = 0;
for (ll i = strlen(str) - 1; i >= 0; i--)
digit[++len] = str[i] - 0;
return dfs(len, true, 0, -1, false);
}
void init() {
memset(dp, -1, sizeof dp);
}
int main() {
int t;
scanf("%d", &t);
init();
while (t--) {
char n[NN];
scanf("%s", n);
printf("%lld
", solve(n));
}
return 0;
}
