Description
For example, the first 80 digits of the sequence are as follows:
11212312341234512345612345671234567812345678912345678910123456789101112345678910
Input
Output
Sample Input
2 8 3
Sample Output
2 2
思路:设三个数组,n[i]表示数字i的长度,c[i]表示在字符串1234567891011....中数字i的结束位置,s[j]表示前j个字符串的长度,其中,第j个字符串以j结尾。
c[i] = c[i-1]+n[i] s[i] = s[i-1]+c[i]
1 | 2 | 9 | 10 | 11 | |
n | 1 | 1 | 1 | 2 | 2 |
c | 1(1) | 2(12) | 9 (123456789) | 11(1234567891011) | 13(1234567891011) |
s | 1(1) | 3(112) | 45(112123123412345123456 123456712345678123456789) | 56(1121231234123451234561234567 1234567812345678912345678910) | 69(1121231234123451234561234567 12345678123456789123456789101234567891011) |
采用二分查找,设输入为num
首先从s数组中,查找num所在的第j个串,s[j]>=num && s[j-1]<num ,更新num的值为num -= s[j-1];
然后从数组c中确定为该串的哪一个数字,c[j] >= num && c[j-1] < num,更新num的值为num -=c[j-1]
到这一步,已经确定了num所在的数字以及为该数字的第几位,求出即可。
补充一个函数 lower_bound(),二分查找,数据升序排列
头文件:#include<algorithm>
使用 lower_bound(array,array+size,num) 返回数组array中第一个大于等于num的数,搜索区间[array,array+szie),左闭右开,如果所有元素均小于num,则返回array+size,返回的是指针。
使用:int index = lower_bound(array,array+size) - array; index为下标。
upper_bound(array,array+size,num) 返回数组array中第一个大于num的数
bool binary_search(array,array+size,num):二分查找,检查某个元素是否存在,
#include<iostream>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
long long s[52850];
int c[52850],n[52850];
//s表示每一个串的长度 c[i]表示数字i在确定的串中的位置
int length(int i){
if(i < 10)
return 1;
if(i <100)
return 2;
if(i <1000)
return 3;
if(i < 10000)
return 4;
return 5;
}
void init(){
s[0] = 0;
c[0] = 0;
for(int i = 1; i <= 52849; i++){
n[i] = length(i);
c[i] = c[i-1]+n[i];
s[i] = s[i-1]+c[i];
}
}
int main(){
int total_cases,left;
cin>>total_cases;
init();
while(total_cases--){
int num;
cin>>num;
//二分查找 lower_bound upper_bound binary_search
left = lower_bound(s+1,s+52845,num) - s; //返回第一个大于等于num的值
num -= s[left-1];
left = lower_bound(c+1,c+left,num) - c;
num-=c[left-1];
num = n[left] - num+1;
while(--num > 0)
left/=10;
cout<<left%10<<endl;
}
}