【问题描述】
定义一种特别的数字,它的左半部分和它的右半部分完全一样,例如2020,它的左半部分和右半部分都是20,是一个特别的数字。
注意:数字202不是特别的数字,数字2112也不是特别的数字。
现在请你求出区间[1,n]的这n个数中,有多少个特别的数字。
【输入形式】
输入整数n。
【输出形式】
输出一个整数,表示区间[1,n]的这n个数中特别的数字的数量。
【样例输入】
22
【样例输出】
2
【样例说明】
[1,22]这22个数中,只有11和22是特别的数字,因此输出2
【评分标准】
对于20%的数据,保证1<=n<=100
对于40%的数据,保证1<=n<=100000
对于60%的数据,保证1<=n<=1e9
对于100%的数据,保证1<=n<=1e18
解题思路
数据范围很大不能枚举判断每一个数
所以寻找数字的规律
每一个这样的特别数字都是由一个1~1e9之间的数构成的
比如:32可以构成3232,789可以构成789789…
那么你要判断[0,n]之间有多少个这样的特别数字,就只需要判断小于n的最大的特别数字是多少
若n的位数是奇数,例:n = 12345, 那么10000 - 12345之间都是没有特别数字的,所以可以把n看作9999,那就可知区间内有99个特别数字
若n的位数是偶数,那么分为两种情况。
- 左边大于右边:例:4332,那么最大的特别数字应该是4242(左半部分数字减一)
- 左边小于右边:例:2345,那么最大的特别数字应该是2323(就是左半部分数字)
由此就找到了数的规律,至于代码实现中将n作为字符串输入可以更方便的获取数的位数
经验总结
- 获取一个大整数的位数,输入时输入为string,通过string.length()获取更加的方便
- string转换成数字
方法一
#include <string>
string a;
int b = stoi(a); // 将字符串a转换成数字b
方法二
#include <sstream>
string a;
stringstream stream(a);
int b;
stream >> b; // 将字符串a转换成数字b
- 字符串string可以直接通过小于大于符号进行比较
- string.substr(x, y)函数,截取string从 x 位开始的 y 个字符(首位算第0位)
代码实现
#include <iostream>
#include <algorithm>
#include <string>
#include <cmath>
#include <sstream>
using namespace std;
int main()
{
string a;
cin >> a;
if(a.length() % 2)
{
for (int i = 0; i < (a.length() / 2); i ++) cout << 9;
}
else
{
string left = a.substr(0, (a.length() / 2));
string right = a.substr(a.length() / 2, (a.length() / 2));
if(left <= right) cout << left;
else
{
//将string转换成int
int b = 0;
stringstream stream(left);
stream >> b;
cout << b - 1;
}
}
return 0;
}