UVa 10706 Number Sequence
来源:互联网 发布:js点击空白处隐藏 编辑:程序博客网 时间:2024/04/30 15:24
/*思路: 二分法求出k值, 再对sk二分法求出所在数值, 最后确定所在位*/#include <cstring>#include <cstdio>#include <cmath>using namespace std;int s1[] = {0, 45, 9045, 1395495, 189414495}; // 前0项 前9项 前99项 前999项 前9999项位数和int s2[] = {0, 9, 189, 2889, 38889}; // s0 s9 s99 s999 s9999的位数int s3[] = {0, 9, 99, 999, 9999};void getxy(int &x, int &y, int d){ x = 1; y = 9; while(d-->1) { x *= 10; y = y*10 + 9; }}void guess(int n, int d){ int x, y; getxy(x, y, d); //获得二分法上下界 //二分法算出k值(存在x中) double sum = n - s1[d-1]; // sum开始计算的位数 int a = s3[d-1]; //a, b, sf 求和参数 int b = s2[d-1]; int sf = b + d; //sf第一项位数 double s; while(x < y) { int m = x + (y-x)/2; int sm = (m - a)*d + b; s = floor(1.0*(sm+sf)*(m-a)/2 + 1e-9); //等差数列求和公式 if(abs(s - sum) < 1e-9) { x = m; break; } if(s - sum > 1e-9) y = m; else x = m+1; } int sb = (x-a-1)*d + b; //x的前一列 s(k-1)所有位数 s = floor(1.0*(sb+sf)*(x-a-1)/2 + 1e-9); int left = floor(sum - s + 1e-9); for(d=0; d<5; d++) { if(left <= s2[d]) break; } left -= s2[d-1]; //二分法算出Sk中的第几项 getxy(x, y, d); int cnt; int sx = x; while(x < y) { int m = x + (y-x)/2; cnt = (m-sx+1)*d; //等差数列求和公式 if(cnt == left) { x = m; break; } if(cnt > left) { y = m; } else { x = m+1; } } //判断在x第几位 cnt = left - (x-sx)*d -1; char buff[6]; sprintf(buff, "%d", x); printf("%c\n", buff[cnt]);}int main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int T; scanf("%d", &T); int n; while(T--) { scanf("%d", &n); int d; for(d=0; d<5; d++) { if(n <= s1[d]) break; } guess(n, d); } return 0;}