Nature Numbers hiho一下 第180周

来源:互联网 发布:网络电视直播播放器 编辑:程序博客网 时间:2024/06/10 08:17

题意: 将自然数从 0 开始一直往后写,形成一个数组:”012345678910111213…”。求数组的第 N 位上的数字是几,数组从下标为 0 开始,即第 0 位上的数字是 0,第 1 位上的数字是 1,以此类推。

思路: N 的范围较大,考虑如何减少时间复杂度。稍微列举下我们能够写出 1 位数的下标范围、2 位数的下标范围等,然后我们能够发现 17 位数的下标范围的右端点就已经超出了 1018

要求第 N 个位置上的数字是几,我的思路是求出第 N 个位置对应的数和第 N 个位置上的数字是当前数的第几位。
举个例子,当 N = 17 时,情况如下图:

N = 17 对应的数是 13 的 从右往左数的第一位数 3。

代码:

#include<cstdio>#include<cstring>#include<cstdlib>#include<stack>#include<queue>#include<utility>#include<vector>#include<cmath>#include<set>#include<map>#include<iostream>#include<algorithm>#include<sstream>using namespace std;typedef long long LL;const LL base[] = {1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18}; //存储 10 的 i 次方LL t[20][2]; //t[i][0] 表示当前段左端点下标,t[i][1] 表示当前段右端点下标LL N;//返回数 num 从右往左数的第 pos 位上的数字LL Colc(LL num, LL pos){    while(pos > 1){        num /= 10;        pos--;    }    return num % 10;}int main(){    //产生每段的范围    t[1][0] = 0; t[1][1] = 9;    for(LL i=2; i<=17; i++){        t[i][0] = t[i-1][1]+1;        t[i][1] = t[i-1][1]+9*base[i-1]*i;    }    while(scanf("%lld", &N) == 1){        LL dig;  //dig 表示下标为 N 的位置对应的数字是 dig 位数        for(dig=1; dig<=17; dig++){            if(N >= t[dig][0] && N <= t[dig][1])                break;        }        if(dig == 1){  //如果是 1 位数            printf("%d\n", N);        }else{         //不是 1 位数            LL num = base[dig-1]+(N - t[dig][0])/dig;  //num 表示下标为 N 的位置对应的数字是多少            LL pos = (N - t[dig][0])%dig;            pos = dig - pos;  //pos 表示下标为 N 的位置上的数字是当前对应数从右往左数的第 pos 位上的数字            printf("%lld\n", Colc(num, pos));        }    }    return 0;}