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;
    }
  • 相关阅读:
    dgango
    django
    pymysql 增删改 查 索引
    mysql 单表,多表,符合条件,子查询
    mysql 数据的增删改
    mysql foreignkey
    mysql基础知识之数据类型与约束
    MySol序
    MySql
    Python Selenium 常用方法总结
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11574054.html
Copyright © 2011-2022 走看看