看到位数最大为2147483647,考虑寻找规律进行打表。
1~9:每次增加一位,那么占的总位数为45
10~99:每次增加二位,那么占的总位数为9000
100~999:每次增加三位,那么占的总位数为1387800
1000~9999:每次增加四位,那么占的总位数为18979200
此时总的位数为45+9000+1387800+18979200 = 20376045 < 2147483647
10000~99999:每次增加5位,那么占的总位数为22009140000 比 2147483647还要多一位。
所以我们要找规律,增加的位数规律为log10(i)+1。可以用数组存储起来,先来用程序算下总共需要多大的数组:
#include<math.h>
#include<iostream>
using namespace std;
unsigned int a[100000];
unsigned int sum[100000];
int main(){
a[1] = 1;
sum[1] = 1;
int i;
for(i = 2;i<100000;i++){
a[i] = a[i-1]+(int)log10((double)i)+1;
sum[i] = sum[i-1]+a[i];
if(sum[i] > 2147483647)
break;
}
cout<<i<<endl;
return 0;
}
输出为31268.
那么有了数组如何计算所在位的数字呢,先确定位数是在哪个组中(一个序列为一组,比如12为一组,123456789也为一组),然后算出在这个组中的位移偏量。从所在组的第一位开始,直到算出所在数字,然后再求其位数是什么,代码如下:
#include<math.h>
#include<iostream>
using namespace std;
const int size = 31269;
unsigned int a[size];
unsigned int sum[size];
int main(){
//初始化
a[1] = sum[1] =1;
for(int i =2;i<size;++i){
a[i] = a[i-1]+(int)log10((double)i)+1;
sum[i] = sum[i-1]+a[i];
}
int m,n;
cin>>n;
while(n != 0){
cin>>m;
int i =1;
//算出在哪个组中
while(m >sum[i])
i++;
//位移偏量
int len = m-sum[i-1];
int pos = 0;
//找到所在组中的数字
for(i =1; pos<len;i++)
pos = a[i];
//之前i多了一位是pos>len,所以要减去,这里是已知数字,求
//所在位数,比如1234,求3,那么就是(1234/10)%10
int result = (i-1)/(int)pow((double)10,(pos-len))%10;
cout<<result<<endl;
n--;
}
}
打表果真够快,速度是0ms