UVa 10706 - Number Sequence(POJ 1019)

29 篇文章 0 订阅
3 篇文章 0 订阅

乍一看数据范围真是有点吓人,单纯暴力肯定超时。观察数字可以找到规律:

数字范围          数字位数范围    每个数字宽度   总共数字所占位数

1~9 :              1~9.                     1                      45

10~99:           11~189                 2                      9000

100~999:       192~2889              3                     1386450

10000~9999:    2893~38889          4                     1881019000  

>=100000         38894 ~ *              5                      **

找出输入数字所在的数字位数范围,再进一步确定他具体所在的数字位数,再进行枚举。

比如说:输入 9045,由上表先可以确定它是在11~189数字位数范围内,再进一步可以确定他是在189(即:从1到99)这个位数范围里的,最后进行枚举,发现他恰好189这个位数范围内的数字99的个位上,因此输出 9 。

代码如下:

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>

using namespace std;

void solve(int num, int en,int start, int t)
{
    int sta = start, j;
    long long i, sum = 0;
    char b[6];
    for(i = 0; i <= en; sta += t) // 先确定所求位数所在的具体数字范围,如:上述例子中其所在范围为数字1~189
    {
        i += sta;
        if(num <= i)
        {
            i -= sta;
            break;
        }
    }
    int len, cnum = num - i;
    for(j = 1;; j++)    // 枚举到相应位数,上例中是从1一直枚举到99的个位数字9
    {
        len = (int)log10(j) + 1;
        sum += len;
        if(sum >= cnum)
            break;
    }
    sum -= len;
    sprintf(b, "%d", j);
    printf("%c\n", b[cnum- sum - 1]);
}
int main()
{
#ifdef test
    freopen("in.txt", "r", stdin);
#endif
    int t;
    int num;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &num);
        if(num <= 45)    // 确定数字大致所在的位数范围,由此确定其每位数字的宽度等条件
            solve(num, 45, 1, 1);
        else if(num <= 9000 + 45)
        {
            num -= 45;  // 减去前面的数字范围(即进去不同数字宽度的总位数,只走当前数字宽度所在的位数范围)
            solve(num, 9000, 11, 2);
        }
        else if(num <= 1386450 + 9045)
        {
            num -= 9045;
            solve(num, 1386450, 192, 3);
        }
        else if(num <= 188019000 + 1386450 + 9045)
        {
            num -= 1386450 + 9045;
            solve(num, 188019000, 2893, 4);
        }
        else
        {
            num -= 188019000 + 1386450 + 9045;
            solve(num, 2147483647, 38894, 5);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值