信息学奥赛一本通提高篇 1586:【 例 2】数字游戏 数位动态规划
·
1586:【 例 2】数字游戏
时间限制: 1000 ms 内存限制: 524288 KB
【题目描述】
科协里最近很流行数字游戏。某人命名了一种不降数,这种数字必须满足从左到右各位数字成小于等于的关系,如 123,446。现在大家决定玩一个游戏,指定一个整数闭区间 [a,b],问这个区间内有多少个不降数。
【输入】
有多组测试数据。每组只含两个数字 a,b,意义如题目描述。
【输出】
每行给出一个测试数据的答案,即 [a,b] 之间有多少不降数。
【输入样例】
1 9
1 19
【输出样例】
9
18
【提示】
数据范围与提示:
对于全部数据,1≤a≤b≤2^31−1。
【解析】
数位动态规划,详见代码:
#include<bits/stdc++.h>
using namespace std;
int dp[12][12];//dp[i][j]表示第i位为j时有多少个不降数
int a, b;
vector <int> digit;
//从第pos位为statu开始搜索,done表示是否有限制0,无限制,1,有限制
int dfs(int pos, int statu, int done) {
if (pos == -1) return 1; //搜索到第-1位,即搜索完毕
//无限制,并且已经搜索完成了,直接返回结果
if (!done && (dp[pos][statu] != -1)) return dp[pos][statu];
int ret = 0; //初始化计算结果
int e;//下一位结束数字
if (done == 0) { //无限制,到9
e = 9;
} else { //有限制,到这一位数字
e = digit[pos];
}
//枚举当前位开始数字到结束数字
for(int i = statu; i <= e; i++) {
//递归计算下一位,如果当前有限制,且是最大数,则下一位也有限制
ret += dfs(pos - 1, i, done && i == e);
}
//如果无限制,记录无限制的数值
if (!done) dp[pos][statu] = ret;
return ret;
}
//计算小于等于x的不降数数量
long long solve(int x) {
memset(dp, -1, sizeof(dp)); //初始化dp数组
digit.clear();//数字清空
while(x > 0) { //拆位
digit.push_back(x % 10);
x /= 10;
}
//递归计算
return dfs(digit.size() - 1, 0, 1);
}
int main() {
while(cin >> a >> b) {
cout << solve(b) - solve(a - 1) << endl;
}
return 0;
}
更多推荐



所有评论(0)