乍一看数据范围真是有点吓人,单纯暴力肯定超时。观察数字可以找到规律:
数字范围 数字位数范围 每个数字宽度 总共数字所占位数
1~9 : 1~9. 1 45
10~99: 11~189 2 9000
100~999: 192~2889 3 1386450
10000~9999: 2893~38889 4 1881019000
>=100000 38894 ~ * 5 **
找出输入数字所在的数字位数范围,再进一步确定他具体所在的数字位数,再进行枚举。
比如说:输入 9045,由上表先可以确定它是在11~189数字位数范围内,再进一步可以确定他是在189(即:从1到99)这个位数范围里的,最后进行枚举,发现他恰好189这个位数范围内的数字99的个位上,因此输出 9 。
代码如下:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
using namespace std;
void solve(int num, int en,int start, int t)
{
int sta = start, j;
long long i, sum = 0;
char b[6];
for(i = 0; i <= en; sta += t) // 先确定所求位数所在的具体数字范围,如:上述例子中其所在范围为数字1~189
{
i += sta;
if(num <= i)
{
i -= sta;
break;
}
}
int len, cnum = num - i;
for(j = 1;; j++) // 枚举到相应位数,上例中是从1一直枚举到99的个位数字9
{
len = (int)log10(j) + 1;
sum += len;
if(sum >= cnum)
break;
}
sum -= len;
sprintf(b, "%d", j);
printf("%c\n", b[cnum- sum - 1]);
}
int main()
{
#ifdef test
freopen("in.txt", "r", stdin);
#endif
int t;
int num;
scanf("%d", &t);
while(t--)
{
scanf("%d", &num);
if(num <= 45) // 确定数字大致所在的位数范围,由此确定其每位数字的宽度等条件
solve(num, 45, 1, 1);
else if(num <= 9000 + 45)
{
num -= 45; // 减去前面的数字范围(即进去不同数字宽度的总位数,只走当前数字宽度所在的位数范围)
solve(num, 9000, 11, 2);
}
else if(num <= 1386450 + 9045)
{
num -= 9045;
solve(num, 1386450, 192, 3);
}
else if(num <= 188019000 + 1386450 + 9045)
{
num -= 1386450 + 9045;
solve(num, 188019000, 2893, 4);
}
else
{
num -= 188019000 + 1386450 + 9045;
solve(num, 2147483647, 38894, 5);
}
}
return 0;
}