• CSP-M2-C-咕咕东的奇妙序列


    题意:
    咕咕东 正在上可怕的复变函数,但对于稳拿A Plus的 咕咕东 来说,她早已不再听课,此时她在睡梦中 突然想到了一个奇怪的无限序列:112123123412345 …这个序列由连续正整数组成的若干部分构成,其 中第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所 有数字,第i部分总是包含1至i之间的所有数字。所以,这个序列的前56项会是 11212312341234512345612345671234567812345678912345678910,其中第1项是1,第3项是2,第20项是 5,第38项是2,第56项是0。咕咕东 现在想知道第 k 项数字是多少!但是她睡醒之后发现老师讲的东西 已经听不懂了,因此她把这个任务交给了你。

    输入格式:
    输入由多行组成。
    第一行一个整数q表示有q组询问
    接下来第i+1行表示第i个输入 ,表示询问第 项数字。

    输出格式:
    输出包含q行
    第i行输出对询问 的输出结果。

    数据范围:

    样例输入:

    5 1 3 20 38 56

    样例输出:

    1 2 5 2 0

    思路:二二分

    每次查找第k位,先确定它位于哪个大组,即与b[i]进行比较。k减去所在大组前面的位数之后可以得到在当前大组中的位数,同时得到该数据所处大组中的上下界。
    在一个大组中查找k这时数据量还是十分庞大,怎么简化操作?由于一个大组中每个小组的位数都是有序的(相差方差个),所以可以使用二分法。
    在大组中通过二分查找每一个小组的位数,确定k所在的小组。
    一个小组内还可以继续分组,同样位数有序可以继续使用二分法继续查找,减去前面的a[i]剩余的是与其位数相等的数,在这里面确定是第几个数字的第几位。

    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define ll long long
    using namespace std;
    ll gets(long long mm,int opt)
    {
        ll sum=0,cnt,add=0,len=0,exam=1;
        while(1)
        {
            exam*=10;
            len++;
            if(mm>exam-1)
            {
                cnt=exam-exam/10;
                if(opt)
                {
                    sum+=add*cnt+cnt*(cnt+1)/2*len;
                    add+=cnt*len;
                }
                else
                {
                    sum+=cnt*len;
                }
            }
            else
            {
                cnt=mm-exam/10+1;
                if(opt)
                {
                    sum+=add*cnt+cnt*(cnt+1)/2*len;
                    add+=cnt*len;
                }
                else
                {
                    sum+=cnt*len;
                }
                break;
            }
        }
        return sum;
    }
    int main()
    {
        int q;
        ll k;
        ll ans=0;
        scanf("%d",&q);
        while(q--)
        {
            ans=0;
            scanf("%lld",&k);
            ll l=0,r=1e9;
            while(l<=r)
            {
                ll mid=(l+r)>>1;
                if(gets(mid,1)<k)
                {
                    l=mid+1;
                    ans=mid;
                }
                else
                {
                    r=mid-1;
                }
            }
            k-=gets(ans,1);
            l=0;
            r=ans+1;
            while(l<=r)
            {
                ll mid=(l+r)>>1;
                if(gets(mid,0)<k)
                {
                    l=mid+1;
                    ans=mid;
                }
                else
                {
                    r=mid-1;
                }
            }
            k-=gets(ans,0);
            ans+=1;
            //printf("ans=%lld,k=%lld
    ",ans,k);
            cout<<to_string(ans)[k-1]<<endl;
        }
    }
  • 相关阅读:
    聚集索引
    第一天 尝试Thread
    sql 分区函数
    sql 查询表定义
    千万数量级分页存储过程
    成语解释
    sql 分组查询满足条件所以数据
    sql存储过程
    联表更新的反思
    从表保存了主表的id,以分号分隔,怎么样用一条sql搞定主表满足条件的查询? 不希望单独写存储过程,或者后台拆成int后传进来,就一条sql 搞定,一条
  • 原文地址:https://www.cnblogs.com/liuzhuan-xingyun/p/13048790.html
Copyright © 2020-2023  润新知