ググドンの素晴らしいシーケンス

タイトル:
ググドンの素晴らしいシーケンスタイトル:
ここに画像の説明を挿入
入力:
ここに画像の説明を挿入
出力:
ここに画像の説明を挿入
サンプル:ここに画像の説明を挿入

問題解決のアイデア:この問題は依然として非常に困難です。主にデータが大きすぎるため、接頭辞を使用して最初の6つのポイントしか渡せない場合、1e18は冗談ではなく、数値を組み立てることができません。これが私の考えです:最初に、最初にサイズ8の配列を作成し、1〜10の数値を格納します^ I:たとえば
、配列の最初の要素は
112123123412345 ... 123456789サイズは45 です
配列2番目の要素は
112123 ... 123 ... 9123 ... 10123 ... 11 ... 123 ... 99から99
第三の要素999
8つの要素(要素が1E18第より大きいされているため、そのため第8要素まで)まで
I少ない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;
    }
}
PGZ
元の記事を34件公開しました 賞賛されました0 訪問862

おすすめ

転載: blog.csdn.net/qq_43653717/article/details/105396217