【POJ 1019】 Number Sequence

【POJ 1019】 Number Sequence


二分水题 放组合数学里。。。可能有什么正规姿势吧Orz


112123123412345...这种串 分成长度1 2 3 4 5...的串 注意有多位数

把长度累加到一个数组里 注意要累加 因为查询的时候查的是原串中对应位置的数 因此要累加上前一次的长度 然后二分处该串前的总长 用查询的位置-之前串的总长 就是在最长的串中的位置 因此还要打个最长串的表


这些我都写一个循环里了 看着有点乱 可以拆开写。。。


代码如下:


#include <iostream>
#include <cstdio>
#include <cstdlib>
#define ll long long
#define INF 2147483648

using namespace std;
//2147483647
ll r[33333];   //二分查的数组
char str[233333]; //最长串的表
int tp,len;                     //累计二分数组长度 和最长串长度

void Init()
{
    int i,j,cnt,pw,k,s;
    r[0] = 0;
    len = 1;          //最长串从1开始 便于查询
    for(tp = 1, i = 1, j = 1, cnt = 1, pw = 10; r[tp-1] <= 2147483647; i += cnt, tp++) //i累计当前串长 cnt累计最后一个数长度  j累计最后一个数(多位数) pw最后一个数位(1 10 100 100...)
    {
        r[tp] = r[tp-1] + i;
        k = j;
        s = pw/10;
        while(s)
        {
            str[len++] = k/s + '0';
            k%=s;
            s /= 10;
        }

        ++j;
        if(j/pw)
        {
            pw *= 10;
            cnt++;
        }
    }
    tp--;
    r[tp] = INF;
}

int main()
{
    int l,rr,ans,t,mid;
    ll pos;
    Init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&pos);
        l = ans = 0, rr = tp;

        while(l <= rr) //二分查找
        {
            mid = l+rr>>1;
            if(r[mid] < pos)
            {
                ans = mid;//小于查询位置的数中最大的 注意不可等
                l = mid+1;
            }else rr = mid-1;
        }
        printf("%c\n",str[pos-r[ans]]);
    }
    return 0;
}


你可能感兴趣的:(二分)