POJ 1019 number sequece数学处理

题意很简单,数列构造如下11212312341234561234567...

给出任意位数n,要求找出第n位是几

第一次做的时候钻牛角尖了,结果wa了好久也不过,后来整理了下思路,发现并不困难

首先我们定义,ai为一个序列,其内容为从1到i所有整数写出所形成的数字序列,例如a6=123456 ,a11=1234567891011,以此类推。

给出一个n,分以下几个步骤得到答案:

①先确定第n位处于的“序列号”,即ai,同时就可以确定这个数字是在序列ai的第几位,这个只需要用n减去前(i-1)个a序列的总长度即可。为此我们要做预处理,生成ai的长度存在数组里,并维护一个前缀和数组,规模35000就足够了,因为题目中最多要求到21亿,35000的规模可以生成26亿数字大概。

②再确定这个数字是属于序列ai中的哪个整数p,由我们的定义,这个整数一定介于[1,i],这个用循环即可实现,复杂度并不高。

③再确定这个数字是整数p的 第几位,道理类似,得到了这个信息就可以求得那个数字了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cstdlib>
//#include<windows.h>

#define maxn 201314
#define inf 0x3f3f3f3f
#define LL long long

using namespace std;
int t;
int n;
LL digit[35010];
LL sum_digit[35010];
int ppow(int m,int n)//replace for pow function,which will not be compiled in POJ.
{
    int ans=1;
    for(int i=1;i<=n;i++)
    {
        ans*=m;
    }
    return ans;
}
void init()//get the length of every sequence,meanwhile we update a prefix sum .
{
    memset(digit,0,sizeof(digit));
    memset(sum_digit,0,sizeof(sum_digit));
    int flag=1;
    for(int i=1;i<=35000;i++)
    {
        int tmp=i;
        int d=0;
        while(tmp)//for each i ,we get the digits of i
        {
            tmp/=10;
            d++;
        }
        for(int j=0;j<=(d-2);j++)
        {
            digit[i]+=(j+1)*9*((int)ppow(10,j));
        }
        digit[i]+=d*(i-(int)ppow(10,d-1)+1);
        sum_digit[i]=sum_digit[i-1]+digit[i];
    }
}
int getdit(int i)
{
    int ans=0;
    while(i)
    {
        i/=10;
        ans++;
    }
    return ans;
}
int main()
{
    init();
    //cout<<sum_digit[35000]<<endl;
    //have successfully get digit for sequence i
    cin>>t;
    while(t--)
    {
        cin>>n;
        int num=-1;
        //step 1
        for(int i=1;i<=35000;i++)
        {
            if(sum_digit[i]>=n&&sum_digit[i-1]<n){
                num=i;
                break;
            }
        }
        n-=sum_digit[num-1];
        //step 1 finished
        //now we'll find the nth digit of "sequence num"
        //cout<<n<<endl;
        int p=0;
        int numnum;
        int tmp=n;
        //cout<<num<<" "<<n<<endl;
        //step 2
        for(int i=1;i<=num;i++)
        {
            p+=getdit(i);
            if(p>=n)
            {
                numnum=i;
                tmp-=(p-getdit(i));
                break;
            }
        }
        //step 2 finished
        //cout<<numnum<<endl;
        //cout<<tmp<<endl;
        //now we'll find the tmp-th digit of the integer numnum.
        int ttmp=getdit(numnum);
        int ans=-1;
        //step 3
        for(int i=1;i<=(ttmp+1-tmp);i++)
        {
            ans=numnum%10;
            numnum/=10;
        }
        //step 3 finished
        cout<<ans<<endl;
    }
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值