zoukankan      html  css  js  c++  java
  • Codeforces 1216E Numerical Sequence 二分

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

    题意:有一个无限长的数字序列,其组成为1 1 2 1 2 3 1.......1 2 ... n...,即重复的1~1,1~2....1~n,给你一个k,求第k(1e18)个数字是什么

    分析:首先,我们先来大致算一下大概有多少个块(一个块值一次1到i)我们假设第i块的长度为i(事实上要更大,因为到了后面,有两位数,三位数...),这样算出来,前n块的和要达到1e18的话,n大致为1e9(等差数列求和是平方的复杂度),我们就必须找到一个较快的速度找到它属于第几块

    因为前i+1块的和肯定是大于前i块的和的,也就是说单增,我们可以用二分来处理这个问题,具体看代码

    几个难懂的地方:

    add值的是比当前长度短的数的和,比如当长度为3时,所有长度为2的数的长度和为189(1-9,10-99)

    cnt*(cnt+1)/2*len是因为我们我们求的是1个当前长度,2个当前长度的数一直到cnt个当前长度的数,也就是等差数列求和,然后再乘个len就好

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+7;
    const int N=1e3+7;
    const int inf=0x3f3f3f3f;
    ll k;
    ll get(ll x){
        return x*(x+1)/2;
    }
    ll sumto(int x,int need){
        ll sum=0;
        ll add=0;
        ll p=1;
        for(int len=1;;len++){
            if(p*10-1<x)
            {
                ll cnt=p*10-p;//长度为Len的数字的个数
                if(need){
                    //get(cnt)*len是长度为len的数字的总长度,但因为每个数字都是从1开始的,前面还有长度为1,2..len-1的总和,这个就是add保存的
                    //一共有cnt*add个需要加 
                    sum+=cnt*add+get(cnt)*len;
                    add+=cnt*len;//每次add存的都是比当前长度小的所有数字的长度和 
                }
                else sum+=cnt*len; 
            }
            else
            {
                ll cnt=x-p+1;
                if(need){
                    sum+=cnt*add+get(cnt)*len;
                }
                else sum+=cnt*len; 
                break;
            }
            p*=10;
        }
        return sum;
    }
    int main(){
        int q;scanf("%d",&q);
        while(q--){
            scanf("%I64d",&k);
            int l=1,r=1e9;
            int res=-1;//求的是第一个和比k大的模块 
            while(l<=r){
                int mid=l+r>>1;
                if(sumto(mid,1)>=k){
                    res=mid;
                    r=mid-1;
                }
                else l=mid+1;
            }
            //cout<<res<<endl;
            //cout<<sumto(res-1,1)<<endl;
            k-=sumto(res-1,1);
            l=1,r=res;
            int ans=-1;
            while(l<=r){
                int mid=l+r>>1;
                if(sumto(mid,0)>=k){
                    ans=mid;
                    r=mid-1;
                }
                else l=mid+1;
            }
            //cout<<ans<<" "<<k<<endl;
            k-=sumto(ans-1,0);
            //cout<<k<<endl;
            cout<<to_string(ans)[k-1]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    convert image to base64 and post to RESTful wcf
    在android webview实现截屏的手动tounchmove裁剪图片
    How to use jquery ajax and android request security RESTful WCF
    using swfUpload in asp.net mvc
    using HttpClient and sending json data to RESTful server in adroind
    ODP.NET数据访问
    android image watermark
    解决国内不能访问github的问题
    idapro权威指南第二版阅读笔记第九章 交叉引用和绘图功能
    idapro权威指南第二版阅读笔记第二章 逆向和反汇编工具
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11574054.html
Copyright © 2011-2022 走看看