题目大意
题目传送门
求数字11212312341234512345612345671234567812345678912345678910123456789101112345678910111212345678910111213…的第i位是几?
思路分析
首先显然这个数列是有规律的,对于前组数据,分别为1,12,123,1234一个比前一个多一位,大于9,后一个比前一个多两位,大于99多三位,于是我们先打表看看到2147483647需要多少组数据,(显然我们不能把整个数列处理了,所以分组是一个不错的选择)
用n[i]
表示
for (int i = 1; i < MAX; i++) {
//这一位是几位数
if (i > 9999)b = 5;//超过四位每次比前一组多5位
else if (i > 999)b = 4;
else if (i > 99)b = 3;
else if (i > 9)b = 2;
else b = 1;
n[i] = n[i - 1] + b;
sn[i] = sn[i - 1] + n[i];
}
可以看到第40000组不到就已经超过3000000000多位了(其实32000就够了),完全是够用了。
因此接下来,我们先要找到输入的数在第几组,然后找到在第几组的第几个数位,然后再找到这个他是这个数中的第几个数即可。
- 找组:我们使用数组
sn
作为每个组位数的前缀和数组,ll index = lower_bound(sn, sn + MAX, b) - sn;
即可找到大于等于输入数字b
的第一组,也即目标所在组。 - 找位:确定了
b
在第i
组,那么b-sn[i-1]
就是b
在第i
组的位置,我们使用以下循环来递增的找到b
所处的数字j
和j
的最后一位的位置len
。
for (j = 1; len < n1; j++)
len += (int)log10(double(j)) + 1;
- 此时我们有
b
的位置n1
,也有·j
的最后一位的位置len
,那么len-n1
就是数字j
中处于b
后面的位数,比如j=123,b=2
多余的位数就是1,我们用 就能把第i位放到个位数上,此时再对10取余即可。
#include<iostream>
#include<stack>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<cmath>
using namespace std;
#define MAX 40000
#define ll long long
ll n[MAX];//枚举每一组有多少位
ll sn[MAX]; // 每组位数的前缀和
string str;
//将k处理成字符串 比如 100:'100'
string rev(ll k) {
string s, t;
while (k > 0) {
t += (k % 10) + '0';
k /= 10;
}
for (int i = t.size() - 1; i >= 0; i--) {
s += t[i];
}
return s;
}
int main() {
ll N, b; cin >> N;
for (int i = 1; i < MAX; i++) {
//这一位是几位数
if (i > 9999)b = 5;//超过四位每次比前一组多5位
else if (i > 999)b = 4;
else if (i > 99)b = 3;
else if (i > 9)b = 2;
else b = 1;
n[i] = n[i - 1] + b;
sn[i] = sn[i - 1] + n[i];
}
for (int i = 0; i < N; i++) {
cin >> b;
ll index = lower_bound(sn, sn + MAX, b) - sn;//找到第一个组数大于等于b的元素,因此元素必在index-1组内
ll num = n[index], n1 = b - sn[index - 1];
ll len = 0, j;
for (j = 1; len < n1; j++)
len += (int)log10(double(j)) + 1;
cout << (j - 1) / (int)pow((double)10, len - n1) % 10 << endl;
//遍历完之后 j是这组中的一个数 j-1是b所在的那个数(数是整体,例如123一百二十三,i刚好等于123,但n指向的可能是1,2或3)
//n1是b在第index组中的位置
//len 是到数j结束的长度
//len-n1是第index组中n1位置后面多余的位数
//所以除以(int)pow((double)10, len - n1); 就是为了将后面的多余位删除
//只要对剩下的数字取模即可
}
}