hiho 180 Nature Numbers

hiho 180

题目1 : Nature Numbers
时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

Consider the following sequence S which is constrcuted by writting nature numbers one by one: “012345678910111213…”.

The first digit of S, S[0], is 0. The second digit S[1] is 1. And the 11th digit S[10] is 1.

Given an integer N, can you find the digit S[N]?
输入

An integer N. (0 <= N <= 1018)
输出

Digit S[N].
样例输入

17

样例输出

3

题目分析:一个直观的解法是从1, 2, 3, … 开始一个数一个数枚举。一开始count=0,保存位数之和。

假设当前枚举到K,我们就把count加上K的位数。如果这时count大于等于N,我们就知道第N位应为K的倒数第N-K+1位。

考虑到N=10^18时,K至少大于10^16,这个算法肯定会超时。

一种优化的思路是不要一个数一个数枚举,而是一批数一批数枚举:每次枚举所有的一位数、两位数、三位数……

一位数有10个(包括0),两位数有90个,三位数有900个……

假设当前枚举到K位数,我们就把count加上(K * K位数的个数)。如果这时count大于等于N,我们就知道第N位是一个K位数的某一位。同时要记录一下count的前一个值pre,pre表示K位数的第一个数的第一位的下标。然后我们可以还原出这个n对应的是K位数的第几个数data,即 data = pow(K-1)+ (n - pre)/k。其中pow(k-1)表示的是K位数的第一个数,(n-pre)/k对应的是第几个K位数。然后利用 (n-pre)% k + 1得到n是data的第几位。最后将data进行分解得到答案。
注意要用 long long

#include <iostream>

using namespace std;

long long pow(long long x)
{
    if(x == 0) return 0;

    long long ans = 1;
    for (long long i = 0; i < x; ++i)
        ans *= 10;

    return ans;
}




int main()
{   

    long long n;

    cin>>n;

    long long  count = 0;
    long long  pre = 0;
    long long  i;

    for ( i = 1 ; ; ++i){

        if ( count <= n){
            pre = count;
            count += i*(pow(i) - pow(i-1));
        }
        else break;

    }

    --i;

    long long  k = i;

    long long  data = pow(i-1) + ((n - pre)/i);

    long long flag = (n - pre)% i + 1;

    long long  res = 0;

    while(data){
        res = data%10;
        data /= 10;
        if(k == flag) break;
        k--;         
    }

    cout<<res<<endl;


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值