题目描述:
题意:你现在有一个序列规律是第n个数时从1到n拼在一起,在把从1到第n个数拼在一起,给定T个n,求序列中第n个字符;
思路分析:其实从网上的搜索结果来看,这道题是有easy和hard两个版本的,easy的数据只到1e9,而hard的数据就到了1e18;
对于easy版本来说,我们就可以开两个数组(设为a,b),第一个(a)记录1~n的总和,第二个(b)记录a的前缀和,我们就可以在一次初始化之后对输入的每个n进行二分查找,找到b中最靠近n的小于n的数,拿n减去这个数之后n剩的就是从1到某个数的总和,或者再多一节,我们可以在a中再次进行二分查找,就可以得出答案了。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 const int N=1e6+10; 6 typedef long long ll; 7 ll b[N],c[N]; 8 int main(){ 9 for(int i=1;i<=600000;++i){ //初始化两个数组 10 int t=1; 11 if(i>=1000000) t=7; //计算i的位数 12 else if(i>=100000) t=6; 13 else if(i>=10000) t=5; 14 else if(i>=1000) t=4; 15 else if(i>=100) t=3; 16 else if(i>=10) t=2; 17 b[i]=b[i-1]+t; 18 c[i]=c[i-1]+b[i]; 19 } 20 int T; 21 scanf("%d",&T); 22 while(T--){ 23 ll n; 24 int flag=0; 25 scanf("%lld",&n); 26 int l=1,mid,r=n; 27 while(l<=r){ //在第二个数组进行二份查找 28 mid=l+(r-l)/2; 29 if(c[mid]<n) l=mid+1; 30 else if(c[mid]>n) r=mid-1; 31 else{ //特判,正好遇到等于的情况直接输出 32 printf("%d\n",mid%10); 33 flag=1; 34 break; 35 } 36 } 37 if(flag) continue; 38 n-=c[r]; 39 l=1;r=n; 40 while(l<=r){ //在第一个数组进行二份查找 41 mid=l+(r-l)/2; 42 if(b[mid]<n) l=mid+1; 43 else if(b[mid]>n) r=mid-1; 44 else{ 45 printf("%d\n",mid%10); 46 flag=1; 47 break; 48 } 49 } 50 if(flag) continue; 51 printf("%d\n",n-b[r]); 52 } 53 return 0; 54 }