poj1019 递推 number sequence

来源:互联网 发布:手机听书软件排行 编辑:程序博客网 时间:2024/05/01 07:14

按这样的方式将字符串分组:1,12,123,...,123...n,... 

用 f【】表示每一组的长度(数字的个数),所以:

   1          ~         9   :   f【i】= f 【i - 1】+ 1;

   10        ~       99     :     f【i】= f 【i - 1】+ 2;

   100       ~       999    :    f【i】= f 【i - 1】+ 3;

    1000     ~    9999    :    f【i】= f 【i - 1】+ 4;

   10000  ~ 99999    :   f【i】= f 【i - 1】+ 5;

同时用sum【】记录前i组总共的数字个数,递推关系为sum【i】= sum【i-1】+ f【i】

#include <iostream>#include <cmath>using namespace std;#define MAXN 31268unsigned int f[MAXN+1], sum[MAXN+1];void init(){    int i;    sum[0] = f[0] = 0;    for (i = 1; i <= 9; i++) { f[i] = f[i-1] + 1; sum[i] = sum[i-1] + f[i]; }    for (i = 10; i <= 99; i++) { f[i] = f[i-1] + 2; sum[i] = sum[i-1] + f[i]; }    for (i = 100; i <= 999; i++) { f[i] = f[i-1] + 3; sum[i] = sum[i-1] + f[i]; }    for (i = 1000; i <= 9999; i++) { f[i] = f[i-1] + 4; sum[i] = sum[i-1] + f[i]; }    for (i = 10000; i <= MAXN; i++) { f[i] = f[i-1] + 5; sum[i] = sum[i-1] + f[i]; }    /*      以上5个for循环可由以下代码代替,写成上面的形式更便于理解。      for (i = 1; i <= MAXN; i++) {          f[i] = f[i-1] + (int)log10(i+0.0) + 1;          sum[i] = sum[i-1] + f[i];      }    */}int BSearch(int l, int r, int tar){    int m;    while (l < r) {        m = (l + r) >> 1;        if (sum[m] < tar) l = m + 1;        else r = m;    }    return l;}int getDigit(int m, int nth) {    int pos = nth - sum[m-1], len = 0, i;    //pos为所求数在第m组中的位置   //从1开始用len记录长度,当长度大于pos后跳出,注意此处其实加到i-1的时候pos>len就不成立了    for (i = 1; pos > len; i++)         len += (int)log10(i+0.0) + 1;// 所求数实际是整数i-1的第len-pos+1位,return后的操作就是取出这一位数  return (i-1)/(int)pow(10.0, len-pos+0.0) % 10;}int main(){    int t, n;    init();     cin >> t;     while (t--) {        cin >> n;        int m = BSearch(1, MAXN, n); //位置n属于第m个分组        cout << getDigit(m, n) << endl;    }    return 0;}




	
				
		
原创粉丝点击