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;}

原创粉丝点击