本题是一道数学,与枚举的题目,所谓形状像山的数字,就是前半段单调不减,后半段单调不增的回文数字,对于本题来说我们需要对数字位数为偶数和奇数的数字分别进行枚举,因为对于偶数位回文来说只要前半段单调不减,后半部分只有一种情况,也就是说偶数回文是完全对称的。而对于奇数位回文来说,除去中间的数字,前后两部分完全对称的前提下,中间的数字就有若干种情况,那么我们枚举的偶数回文和奇数回文的起始和终止是什么呢,对于偶数回文来说,最小的偶数回文是2222,最大的偶数回文是1999999991,对于奇数回文来说,最小的奇数回文是11111,最大的奇数回文是999999999,知道起始和终止之后,我们只需要保证数字的前半部分单调不减,再分别对偶数回文和奇数回文进行处理即可,所以我们写一个检查一个数字是否是单调不减的回调函数,方便后面使用。接着,对于偶数回文的处理,我们前面已经说过了,那么对于奇数回文来说,我们举几个例子,11111,那么中间的数字有9种情况,12221,中间的数字有8种情况,我们发现中间数字的情况数,取决于他前面的数字i,因为要保证前半段单调不减,后半段单调不增,所以中间的情况数即10-(i%10);通过对两种情况下的回文进行处理,我们就可以得到所给区间一共有几个"山"数字
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
/*
回文数字:
前半部分单调不减后半部分单调不增
将一个数字分成两部分讨论,有两种情况一种是这个数字有偶数位,另一种有奇数位
这两种情况分别讨论,分别枚举最小的偶数位数字的前半部分和最大的后半部分
对于偶数位:最小的为22(2222) ,最大为19999 (19999 99991)
对于奇数位:最小的为11(11111),最大为9999 (9999 9 9999)
*/
bool check(int n) {//判断n是否是单调不减
while (n) {
int t = n % 10;
int t1 = n / 10 % 10;
if (t1 > t) return false;
else n /= 10;
}
return true;
}
signed main() {
int cnt = 0;
//偶数位
for (int i = 22; i <= 19999;i++) {
if (check(i)) cnt++;//对于偶数为来说只有完全对称才能是偶数回文,所以后半部分只有一种情况
}
//奇数位
//由于999999999是回文,所以我们最大遍历到8999
for (int i = 11; i <= 8999;i++) {
if (check(i)) cnt += 10 - (i % 10);//对中间的情况有这几种选择,例如11x11,中间就有1-9种选择,x可以是{1....9}
}
cnt++;//9999
cout << cnt;
return 0;
}