Description
A single positive integer i is given. Write a program to find the digit located in the position i in the sequence of number groups S1S2...Sk. Each group Sk consists of a sequence of positive integer numbers ranging from 1 to k, written one after another.
For example, the first 80 digits of the sequence are as follows:
112123123412345123456123456712345678123456789123456789101234567891011
题意:给出一串那样的数字,很有规律的,总共有2147483647位,然后问你第 n 位上的数字是多少。一开始我理解错题意了,以为是问第 n 位的数是多少,WA了2次之后才发觉超过10以后的数字都不止1位了...悲剧
一开始做的复杂了,后来才发现数字的位数可以用 log10((double)i) + 1 这个公式求出来,这样逐步求精就可以慢慢地求出结果了。
1 12 123 1234 12345 123456 1234567 12345678 123456789 12345678910 1234567891011 ......
按上面数列所示,我们把数列分为N段,第N-1段总是第N段的一个子集! 我们首先计算出最长的最大的最后一个段,假设第2147483647位处在第N段,我们则把这个第N段保存下来!
具体做法是用两个数组保存上面的数据,b[ ] 数组保存的是每段数的位数,b[i] 表示第i段位数,a[ ] 数组表示前面所有段的位数,a[i]表示前i段一共有多少位。解题的时候两次二分就可以了。比如查找第N位,先通过数组a[ ] 查找第N位在第几段,算出第几段的第几位,然后通过b[]数组确定第几位是多少。
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
unsigned int a[32000],b[32000];
int main()
{
unsigned int n,m,i,j,k;
for(i=1,k=0;i<31270;i++)
{
b[i]=b[i-1]+(int)log10(double(i))+1;
a[i]=a[i-1]+b[i];
}
scanf("%d",&n);
while(n--)
{
scanf("%d",&m);
unsigned int mm=m-a[lower_bound(a,a+31270,m)-a-1];
unsigned int *p=lower_bound(b,b+31270,mm);
cout<<(p-b)/(int)pow((double)10,(int)(*p-mm))%10<<endl;;
}
}
还有一种方法是:a[]数组存储的信息不变,b[]数组存储的是序列12345678910111213......等各位位数对应数组数组的值,即b[1]=1, b[2]=2, b[3]=3, b[4]=4, b[5]=5, b[6]=6, b[7]=7, b[8]=8, b[9]=9, b[10]=1,b[11]=0, b[12]=1,b[13]=1, b[14]=1,b[15]=1, b[16]=1,b[17]=2, b[18]=1,b[19]=3 .....等,由a数组查询计算出某段的第几位时(比如 i),直接对应输出就可以(b[i]); b数组一个循环就可;
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
long long a[32000],b[200100];
int myitoa(int n,char *s) //itoa不是标准库函数,自己实现个
{
return (n/10&&(*(s+myitoa(n/10,s)+1)=n%10+'0'))?(myitoa(n/10,s)+1):!(*s=n+'0');//这个函数功能就是把数字n转换成字符串而已,具体实现很简单, 不用像我这样写这么长一段话,只是当时好玩才这样写;
}
void ac()
{
long long k=0,i,j;
for(i=1;i<31500;i++)
{
k=k+(int)(log10(double(i)))+1;
a[i]=a[i-1]+k;
}
char c[10];
for(i=1,k=1;i<32000;i++)
{
memset(c,0,sizeof(c));
myitoa(i,c);
for(j=0;j<strlen(c);j++)
b[k++]=c[j]-'0';
}
}
int main()
{
long long n,m;
ac();
scanf("%lld",&n);
while(n--)
{
scanf("%lld",&m);
long long *q=lower_bound(a,a+31400,m);
cout<<b[m-a[q-a-1]]<<endl;
}
return 0;
}