咕咕东的奇妙序列

题目:咕咕东的奇妙序列
题意:
在这里插入图片描述
输入:
在这里插入图片描述
输出:
在这里插入图片描述
样例:在这里插入图片描述

解题思路:这个题还是挺难的,主要是数据太大了,如果用前缀和只能过前六个点,1e18不是闹着玩的,数组装不下的;这里说说我的思路:首先,我先搞个大小为8的数组,存的是从1-10^I的数:
如,数组第一个元素为
112123123412345…123456789大小为45
数组第二个元素为
112123…123…9123…10123…11…123…99到99
第三个元素到999
直到第8个元素(因为第九个元素已经大于1e18了,所以直到第八个元素)
之后,我让给的k减去其中小于k的最大的那个元素;
这时候,k剩下的就是123…(10^I) 123… .(10^i+1)…每个组(即123…x,x之后是1)最后一个元素位数相同;之后用k不停的减去每个组的元素个数,直到k小于那个组的元素个数,但是这里要注意,如果k过大是会超时的;所以我这里采用了二分的方法优化了这个选择的时间;之后剩下的就是一个123…x这样一个组,取其中第k个就行,这里我用的是递归的方法,先用k和9比较,大于9再和180比较(10,11,…99一共180位),大于再继续比较。。。直到小于等于,然后这时候剩下的元素位数都相同(第一个元素一定是10的i次方),你又知道k,求就行了;

代码:

#include<iostream>
#include<cmath>
using namespace std;
long long t[17]={0};
long long h[17]={0};
long long t1[17]={0};
void solve()
{
    h[0]=1;
    for(int i=1;i<=18;i++)
    {
        h[i]=h[i-1]*10;
    }
    t[0]=0;
    t1[0]=0;
    for(int i=1;i<=16;i++)//t1[i]存的是从1-10^i-1的元素的个数
    {
        t1[i]=t1[i-1]+i*(h[i]-h[i-1]);
    }
    for(int i=1;i<=8;i++)//t[i]存的就是从组1到组123...10^1-1的元素的个数
    {
        t[i]=t[i-1]+(h[i]-h[i-1])*t1[i-1]+i*(h[i]-h[i-1])*(h[i]-h[i-1]+1)/2;
    }
}
long long sol1(long long k,int num)
{
    long long t=(h[num]-h[num-1])*num;
    if(k<=t)//小于等于的情况,这时剩下的元素的位数相同,且第一个元素和k已经知道
    {
        long long k1=(k-1)/num;//这里就是求第k的数字
        long long k2=k%num;
        long long n=h[num-1]+k1;
        if(k2==0)
        {
            n=n%10;
            return n;
        }else
        {
            long long u=n;
            int total=0;
            while(u>0)
            {
                u=u/10;
                total++;
            }
            total=total-k2;
            for(int i=0;i<total;i++)
            {
                n=n/10;
            }
            n=n%10;
            return n;
        }
    }else//大于前去递归
    {
        k=k-t;
        return sol1(k,num+1);
    }
}
long long sol(long long k)
{
    long long p;
    for(int i=8;i>=0;i--)
    {
        if(t[i]<=k)
        {
            k=k-t[i];
            p=i;
            break;
        }
    }
    if(k==0){return 9;}//减去那个最大的,如果为0直接返回9就行
    long long p1=t1[p];//这个是减去的那个从1-10^i-1的元素的个数
    p++;
    while(1)
    {
        p1+=p;//这个是1-10^i的元素的个数
        long long l=0,r=1000000000;
        while(l+1<r)//二分
        {
            long long mid=(l+r)/2;
            long long tt=mid*p1+p*(mid-1)*mid/2;
            if(k>tt)
            {
                l=mid;
            }else
            {
                r=mid;
            }
        }
        k=k-(l*p1+p*(l-1)*l/2);//减去,之后剩下的就是123....x
        k=sol1(k,1);//判断
        return k;
    }
}
int main()
{
    solve();
    int q;
    cin>>q;
    while(q--)
    {
        long long k;
        cin>>k;
        long long h1=sol(k);
        cout<<h1<<endl;
    }
}
发布了34 篇原创文章 · 获赞 0 · 访问量 862

猜你喜欢

转载自blog.csdn.net/qq_43653717/article/details/105396217
今日推荐