zoukankan      html  css  js  c++  java
  • CF1216E Numerical Sequence Hard Version 数学

    题目链接 http://codeforces.com/problemset/problem/1216/E2

    分析

    先考虑它的简化版本,对于这样的一个数列,发现它可以拆分成如下的数列。
    (1)
    (12)
    (123)
    (1234)
    (12345)
    这样的话我们维护一个前缀和数组,然后去找第(n)个数字在哪一行,然后减去前边几行的数字数目和就是答案。
    比如(n=5),发现它在第三行,前两行的和为(3)(5-3=2)所以第五个数是(2)
    但如果(n)很大的话,比如这题,就会T掉,首先上述思想是可以肯定的,所以要用更高效的办法
    首先是找到在第几行。
    一行行枚举效率太低,要用到一个分块的思想,按照末位数字的位数分块,这样在每个块里找,枚举每个块的时间复杂度是一个常数,先找到它在哪一块,然后再利用二分的思想确定所在行,因为这个是具有单调性的,那么怎么找呢?
    考虑每一块中有多少个数,用变量(last)记录前几个块的数字和,(len)记录当前枚举的位数,根据等差数列的求和公式((a_1+a_n)*n/2),当前块的第一行的数字和是(last+len)手摸一下就能得出,最后一行是(last+len*cnt),其中(cnt)就是该块内一共有多少数字,如果(n)大于前几块的数字和(sum),就直接减去,否则就找到了所在块,然后再二分求出是那一行就行,求的方法就是不断更新(l和r)判断(sum)(n)的关系,找到后再减去前边几行的和就是第(n)个数字在这一行第几个。
    这时候我们再重复一下上述过程,只不过不是拆分行而是拆分每个数(不是数字),比如12345678910,拆成1 2 3 4 5 6 7 8 9 10,1和0不分开的这种。然后再枚举每个数字的位数,依次减去,从而求出第(n)个数字所在数的位数,最后再把这个数还原出来取它的那个位数就行。

    #include<cstdio>
    #define ll long long
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            ll n;
            scanf("%lld",&n);
            ll last=0,cnt,len;
            for(len=1;;len++){
                cnt=len==1?9:cnt*10;
                ll sum=(last+len+last+len*cnt)*cnt/2;
                if(n<=sum)break;
                n-=sum;
                last+=len*cnt;
            }
            ll l=1,r=cnt,ans;
            while(l<=r){
                ll mid=l+r>>1;
                ll sum=(last+len+last+len*mid)*mid/2;
                if(sum>=n){
                    ans=mid;
                    r=mid-1;
                }else l=mid+1;
            }
            n-=(last+len+last+(ans-1)*len)*(ans-1)/2;
            for(len=1;;len++){
                cnt=len==1?9:cnt*10;
                ll sum=cnt*len;
                if(sum>=n)break;
                n-=sum;
            }
            ll num=(n+len-1)/len;
            n=n-(num-1)*len;
            cnt=1;
            for(int i=1;i<len;i++)cnt*=10;
            num+=cnt-1;
            cnt=len-n+1;
            for(int i=1;i<cnt;i++)num/=10;
            printf("%d
    ",num%10);
        }
        return 0;
    }
    
  • 相关阅读:
    Net设计模式实例之简单工厂模式(Simple Factory Pattern)
    Net设计模式实例系列文章总结
    2019年工作总结
    在Asp.Net Core中集成Kafka(中)
    如何将生产环境的服务Docker镜像拉取到本地进行调试
    记一次EFCore类型转换错误及解决方案
    Asp.Net Core中创建多DbContext并迁移到数据库
    ABP中的AutoMapper
    EFCore中的导航属性
    Asp.Net Core 调用第三方Open API查询物流数据
  • 原文地址:https://www.cnblogs.com/anyixing-fly/p/12789149.html
Copyright © 2011-2022 走看看