poj 1019 Number Sequence
二分, 数学
用分段的思想解决
定义3个数组
len[i]表示i这个数字有多少位,len[1-9] = 1,因为个位数只有1为,len[10-99] = 2,有两位………………
num[i]表示1到i,一共占了几位,num[9]=9,因为123456789,num[10] = 11, 12345678910
sum[i] = num[1]+num[2]…………num[i]
sum[4] = 10 , 因为1121231234
所以对于一个位置n,用分段的思想,不断缩小范围
先找到sum[m] <= n && n < sum[m+1]
然后求出差值 delta = n - sum[m]
然后再在num中查找,num[k] <= delta && delta < num[k+1]
那么最后就能确定到一个数字上
再求差值 __delta = delta - num[k]
表示的是k+1的第__delta个数字是什么
位置最大是2147483647,打表能发现,sum[]数组只要计算到30000多就可以了,所以len,num,sum数组都计算到3万多
对于位置的查找 sum[m] <= n && n < sum[m+1] , num[k] <= delta && delta < num[k+1]
可以顺序查找,因为数据并不大,但是我写了二分查找
最后运行了0ms
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 31500; const int LIM = 2147483647; int len[N+100],num[N+100]; long long sum[N+100]; void Init() { for(int i=1; i<=9; i++) len[i] = 1; for(int i=10; i<=99; i++) len[i] = 2; for(int i=100; i<=999; i++) len[i] = 3; for(int i=1000; i<=9999; i++) len[i] = 4; for(int i=10000; i<=N+10; i++) len[i] = 5; num[1] = sum[1] = 1; for(int i=2; i<=N; i++){ num[i] = num[i-1] + len[i]; sum[i] = sum[i-1] + num[i]; } // for(int i=1 ;i<=10 ;i++) // cout << len[i] << " " << num[i] << " " << sum[i] << endl; } int binsum(int key){ //sum[m] <= key && sum[m+1] > key int low = 1 , high = N; while(low <= high){ int mid = (low + high) >> 1; if(sum[mid] == key) return mid; else if(key < sum[mid]) high = mid - 1; else low = mid + 1; } if(sum[low] <= key) return low; else return high; } int binnum(int key){ //num[m] <= key && num[m+1] > key int low = 1 , high = N; while(low <= high){ int mid = (low + high) >> 1; if(num[mid] == key) return mid; else if(key < num[mid]) high = mid - 1; else low = mid + 1; } if(num[low] <= key) return low; else return high; } void fun(int m){ cout << m%10 << endl; } void __fun(int m ,int delta){ int k = binnum(delta); // cout << k << " " << num[k] << " " << num[k+1] << endl; if(delta == num[k]) fun(k); else{ int __delta = delta - num[k]; int stack[10],top=0; int tmp = k+1; while(tmp){ stack[++top] = tmp%10; tmp /= 10; } for(int i=1,j=top; i<=j; i++,j--) swap(stack[i],stack[j]); cout << stack[__delta] << endl; } } int main(){ Init(); int cas,n; cin >> cas; while(cas--){ cin >> n; int m = binsum(n); int delta = n - sum[m]; if(delta == 0) fun(m); else __fun(m,delta); n++; } return 0; }