poj 1019 Number Sequence

二分, 数学

用分段的思想解决

定义3个数组

len[i]表示i这个数字有多少位,len[1-9] = 1,因为个位数只有1为,len[10-99] = 2,有两位………………

num[i]表示1到i,一共占了几位,num[9]=9,因为123456789,num[10] = 11, 12345678910

sum[i] = num[1]+num[2]…………num[i]

sum[4] = 10 , 因为1121231234

所以对于一个位置n,用分段的思想,不断缩小范围

先找到sum[m] <= n && n < sum[m+1]

然后求出差值  delta = n - sum[m]

然后再在num中查找,num[k] <= delta && delta < num[k+1]

那么最后就能确定到一个数字上

再求差值  __delta = delta - num[k]

表示的是k+1的第__delta个数字是什么

位置最大是2147483647,打表能发现,sum[]数组只要计算到30000多就可以了,所以len,num,sum数组都计算到3万多

对于位置的查找   sum[m] <= n && n < sum[m+1]   ,    num[k] <= delta && delta < num[k+1]

可以顺序查找,因为数据并不大,但是我写了二分查找

最后运行了0ms

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 31500;
const int LIM = 2147483647;
int len[N+100],num[N+100];
long long sum[N+100];

void Init()
{
    for(int i=1; i<=9; i++)        len[i] = 1;
    for(int i=10; i<=99; i++)    len[i] = 2;
    for(int i=100; i<=999; i++) len[i] = 3;
    for(int i=1000; i<=9999; i++) len[i] = 4;
    for(int i=10000; i<=N+10; i++) len[i] = 5;
    num[1] = sum[1] = 1;
    for(int i=2; i<=N; i++){
        num[i] = num[i-1] + len[i];
        sum[i] = sum[i-1] + num[i];
    }
//    for(int i=1 ;i<=10 ;i++)
//        cout << len[i] << "    " << num[i] << "     " << sum[i] << endl;
}

int binsum(int key){
    //sum[m] <= key && sum[m+1] > key
    int low = 1 , high = N;
    while(low <= high){
        int mid = (low + high) >> 1;
        if(sum[mid] == key)        return mid;
        else if(key < sum[mid]) high = mid - 1;
        else                    low = mid + 1;
    }
    if(sum[low] <= key) return low;
    else return high;
}

int binnum(int key){
    //num[m] <= key && num[m+1] > key
    int low = 1 , high = N;
    while(low <= high){
        int mid = (low + high) >> 1;
        if(num[mid] == key) return mid;
        else if(key < num[mid]) high = mid - 1;
        else                    low = mid + 1;
    }
    if(num[low] <= key) return low;
    else                return high;
}

void fun(int m){
    cout << m%10 << endl;
}

void __fun(int m ,int delta){
    int k = binnum(delta);
//    cout << k << "  " << num[k] << "        " << num[k+1] << endl;
    if(delta == num[k]) fun(k);
    else{
        int __delta = delta - num[k];
        int stack[10],top=0;
        int tmp = k+1;
        while(tmp){
            stack[++top] = tmp%10; tmp /= 10;
        }
        for(int i=1,j=top; i<=j; i++,j--)
            swap(stack[i],stack[j]);
        cout << stack[__delta] << endl;
    }
}

int main(){
    Init();
    int cas,n;
    cin >> cas;
    while(cas--){
        cin >> n;
        int m = binsum(n);
        int delta = n - sum[m];
        if(delta == 0) fun(m);
        else           __fun(m,delta);
        n++;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3120814.html