版权声明:本文为博主原创文章,禁止转载。 https://blog.csdn.net/FlushHip/article/details/86644049
题目描述
链接:Here。
假如有一组字符串符合如下规律:
(对于 来说,将从 到 的数字拼接到一起)
现在我们把所有的字符串拼接起来,组成一个无限长的字符串 你能找出该字符串的第 位数字是多少吗?
输入
一个整数( < 整数 < ),表示所求的位数是多少位
输出
一个整数,表示该位上的数字是多少
解析
其实就是要确定第N
位数字所在的项是哪一项。这里分两层。
一层是 的长度,一层是 的长度,分别抽象成 ,观察数字长度的特点就可以知道, 是个特殊的等差数列,而 是特殊的等差数列的前 项和。
公差依次是:
依照这个就可以很容易算出 ,然后利用输入的 二分求上界(可以参考你真的理解二分的写法吗 - 二分写法详解)算出 的最大 ;
利用这个 算出 ,然后利用输入的 二分求上界算出 的最大 ;
利用这个 算出 , 表示整数 的第 位数字,这就是答案了。
这样做应该是最快的解法了。
代码
#include <bits/stdc++.h>
typedef long long LL;
int main()
{
auto calFG = [] (LL n) -> std::pair<LL, LL>
{
LL start = 0, d = 1, nines = 9, sum = 0, res = 0;
for (; sum + nines < n; ++d, sum += nines, nines *= 10) {
res += nines * start + nines * (nines - 1) / 2 * d;
start += nines * d;
}
return { start + d * (n - sum), res + (n - sum + 1) * start + (n - sum + 1) * (n - sum) / 2 * d };
};
auto bFind = [] (LL n, const std::function<LL(int)> & func) -> int
{
int l = 0, r = 1000000;
while (l < r) {
int mid = l + (r - l + 1) / 2;
if (func(mid) < n) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
};
for (LL n; std::cin >> n; ) {
int ii = bFind(n, std::bind([&] (int m) -> LL
{
return calFG(m).second;
}, std::placeholders::_1));
LL res = n - calFG(ii).second;
int i = bFind(res, std::bind([&] (int m) -> LL
{
return calFG(m).first;
}, std::placeholders::_1));
LL ress = res - calFG(i).first;
assert(ress);
std::cout << std::to_string(i + 1).at(ress - 1) << std::endl;
}
return 0;
}