题目描述

The only difference between the easy and the hard versions is the maximum value of k.

You are given an infinite sequence of form "112123123412345……" which consist of blocks of all consecutive positive integers written one after another. The first block consists of all numbers from 1 to 1, the second one — from 1 to 2, the third one — from 1 to 3, ……, the i-th block consists of all numbers from 1 to i.

So the first 56 elements of the sequence are "11212312341234512345612345671234567812345678912345678910". Elements of the sequence are numbered from one. For example, the 1-st element of the sequence is 1, the 3-rd element of the sequence is 2, the 20-th element of the sequence is 5, the 38-th element is 2, the 56-th element of the sequence is 0.

Your task is to answer q independent queries. In the i-th query you are given one integer ki. Calculate the digit at the position ki of the sequence

输入格式

The first line of the input contains one integer q (1≤q≤500) — the number of queries.

The i-th of the following q lines contains one integer ki(1≤ki≤1018) — the description of the corresponding query.

输出格式

Print q lines. In the i-th line print one digit xi (0≤xi≤9) — the answer to the query i, i.e. xi should be equal to the element at the position ki of the sequence.

样例

Input

5
1
3
20
38
56

Output

1
2
5
2
0

Input

4
2132
506
999999999999999999
1000000000000000000

Output

8
2
4
1

提示

Answers on queries from the first example are described in the problem statement.

分析

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

这道题数据范围很大,所以直接枚举是不可行的

我们来分析一下这个数列的性质

因为每个数列都是由重复的1~1,1~2....1~n组成的,所以我们先只看1~n这个数字序列

因为不同位数的数加到序列的后面对序列长度的影响不同

所以我们按一位数、两位数、三位数……n位数来讨论

(要注意的是0不是一位数,因为最高位上的数字不能为零)


当n为一位数时,序列1~1的长度为1

序列1~2的长度为2

序列1~3的长度为3

序列1~4的长度为4

因此1~n的长度为n

我们发现这是一个首项为1,公差为1的等差数列


当n为两位数时,序列1~10的长度为11

序列1~11的长度为13

序列1~n的长度为11+(n-10)$\times$2

我们发现这是一个首项为11,公差为2的等差数列


同样,当n为三位数时,序列的长度是一个首项为192,公差为3的等差数列

依次类推,对于任何位数的数,我们都能把它们写成等差数列的形式

因此我们可以对每一位数的首项进行初始化(公差就是位数)

	now[1]=1;
now[2]=9+2;
now[3]=9+90*2+3;
now[4]=9+90*2+900*3+4;
now[5]=9+90*2+900*3+9000*4+5;
now[6]=9+90*2+900*3+9000*4+90000*5+6;
now[7]=9+90*2+900*3+9000*4+90000*5+900000*6+7;
now[8]=9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+8;
now[9]=9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+90000000*8+9;

now[i]存储的是位数为i时等差数列的首项,最少要预处理到9位

(我感觉这样写比较容易看出规律)


但问题是,题目中是把很多上述序列拼接在一起形成的

所以我们还要将等差数列进行求和

但问题是,每一位数所在的等差数列都不相同

我们在读入时要特判一下当前长度所枚举到的最高位数

	ll cnt=9;
for(int i=1;i<=9;i++){
a[i]=now[i]*cnt+(cnt-1)*(cnt)/2*i;
cnt*=10;
a[i]+=a[i-1];
}

cnt记录的是当前位上最多有多少数字

比如枚举到一位数的话,cnt为9,因为有9个一位数

枚举到两位数的话,cnt为90,因为有90个两位数

我们每一次用等差数列求和公式求出a[i]为刚好枚举完第i位数序列的长度

这样,我们在读入时就可以判断序列枚举到了第几位数


我们在求出枚举到第几位数时,用读入的数减去刚好枚举完上一位数序列的长度

这样方便我们之后的数列求和

因为如果有不同数位的数的话,求和不好求

我们来举一个例子:58

它要比a[1]=45大,比a[2]=9045小,所以它肯定枚举到两位数

我们用58-45=13,求出它枚举到两位数序列的长度

接下来只要我们求出它是前几项和,就能知道它枚举到了第几个两位数

我们一个个去枚举是不可行的,因为等差数列的前n项和具有单调性所以我们要用二分

二分函数返回的是上一个已经枚举完的数

ll solve(ll a1,ll d,ll aa){
ll l=1,r=9,mids;
for(ll i=1;i<d;i++){
r*=10;
}
while(l<=r){
mids=(l+r)/2;
if(ass(mids,d,a1)==aa){
return mids-1;
}
else if(ass(mids,d,a1)<aa) l=mids+1;
else r=mids-1;
}
if(l>r) swap(l,r);
if(ass(r,d,a1)<aa) return r;
else return l;
}

ass函数是求等差数列前n项和的函数

ll ass(ll n,ll d,ll a1){
return n*a1+(n-1)*n/2*d;
}

这样,我们就可以求出该数是第几项和了

还用刚才我们举的例子,我们把13传到二分函数里

\(1\times11+\frac{1\times(1-1)\times2}{2}\)=11<13

\(2\times11+\frac{2\times(2-1)\times2}{2}\)=24>13

所以我们返回1,也就是说以11结尾的序列已经枚举完,我们下面要枚举的是12

我们用13-11得到2

也就是说,以12结尾的序列我们枚举了两位

这时候我们就可以输出2


但是还有一个问题就是,有可能你当前要枚举的数很大,比如7位数甚至8位数

这时候我们就要用一个循环判断该序列的最后一位数是几位数

ll jl=0,bb=9,cc=1;
while(aa>=bb*cc){
jl++;
aa-=(bb*cc);
bb*=10,cc++;
}
jl++;

最后,我们就会得到两个值,该序列枚举到了几位数,该数位所占的长度是多少

刚才的例子剩余2,显然循环结束该序列枚举到了一位数,一位数所占的长度是2

所以我们就输出2

要注意的是长度能否整除位数要分类讨论

代码

细节比较多,大家自己写才能提高代码能力

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=16;
typedef long long ll;
ll a[maxn],now[maxn];
ll ass(ll n,ll d,ll a1){
return n*a1+(n-1)*n/2*d;
}
ll solve(ll a1,ll d,ll aa){
ll l=1,r=9,mids;
for(ll i=1;i<d;i++) r*=10;
while(l<=r){
mids=(l+r)/2;
if(ass(mids,d,a1)==aa) return mids-1;
else if(ass(mids,d,a1)<aa) l=mids+1;
else r=mids-1;
}
if(l>r) swap(l,r);
if(ass(r,d,a1)<aa) return r;
else return l;
}
int main(){
ll t;
scanf("%lld",&t);
now[1]=1;
now[2]=9+2;
now[3]=9+90*2+3;
now[4]=9+90*2+900*3+4;
now[5]=9+90*2+900*3+9000*4+5;
now[6]=9+90*2+900*3+9000*4+90000*5+6;
now[7]=9+90*2+900*3+9000*4+90000*5+900000*6+7;
now[8]=9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+8;
now[9]=9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+90000000*8+9;
ll cnt=9;
for(int i=1;i<=9;i++){
a[i]=now[i]*cnt+(cnt-1)*(cnt)/2*i;
cnt*=10;
a[i]+=a[i-1];
}
while(t--){
ll aa;
scanf("%lld",&aa);
ll ws;
for(ws=1;ws<=9;ws++) if(a[ws]>=aa) break;
aa-=a[ws-1];
ll noww=solve(now[ws],ws,aa);
ll beff=ass(noww,ws,now[ws]);
aa-=beff;
ll jl=0,bb=9,cc=1;
while(aa>=bb*cc){
jl++;
aa-=(bb*cc);
bb*=10,cc++;
}
jl++;
if(aa%jl==0){
aa/=jl;
ll ee=1;
for(ll i=1;i<jl;i++) ee*=10;
aa=ee+aa-1;
printf("%lld\n",aa%10);
} else {
ll ff=aa-aa/jl*jl;
aa/=jl;
ll ee=1;
for(ll i=1;i<jl;i++) ee*=10;
aa=ee+aa;
ll Num[maxn],Ncnt=0;
while(aa){
Num[++Ncnt]=aa%10;
aa/=10;
}
printf("%lld\n",Num[Ncnt-ff+1]);
}
}
return 0;
}

cf1216E2 Numerical Sequence (hard version) 二分查找、思维题的更多相关文章

  1. cf1216E2 Numerical Sequence (hard version)(思维)

    cf1216E2 Numerical Sequence (hard version) 题目大意 一个无限长的数字序列,其组成为\(1 1 2 1 2 3 1.......1 2 ... n...\), ...

  2. Numerical Sequence (easy version)

    http://codeforces.com/problemset/problem/1216/E1 E1. Numerical Sequence (easy version) time limit pe ...

  3. 集训第四周(高效算法设计)N题 (二分查找优化题)

    原题:poj3061 题意:给你一个数s,再给出一个数组,要求你从中选出m个连续的数,m越小越好,且这m个数之和不小于s 这是一个二分查找优化题,那么区间是什么呢?当然是从1到数组长度了.比如数组长度 ...

  4. Leetcode 278 First Bad Version 二分查找(二分下标)

    题意:找到第一个出问题的版本 二分查找,注意 mid = l + (r - l + 1) / 2;因为整数会溢出 // Forward declaration of isBadVersion API. ...

  5. 南理第八届校赛同步赛-F sequence//贪心算法&二分查找优化

    题目大意:求一个序列中不严格单调递增的子序列的最小数目(子序列之间没有交叉). 这题证明贪心法可行的时候,可以发现和求最长递减子序列的长度是同一个方法,只是思考的角度不同,具体证明并不是很清楚,这里就 ...

  6. 集训第四周(高效算法设计)B题 (二分查找优化题)

    ---恢复内容开始--- Description   Before the invention of book-printing, it was very hard to make a copy of ...

  7. Can you find it? HDU-2141 (二分查找模版题)

    Description Give you three sequences of numbers A, B, C, then we give you a number X. Now you need t ...

  8. 【二分】CF Round #587 (Div. 3)E2 Numerical Sequence (hard version)

    题目大意 有一个无限长的数字序列,其组成为1 1 2 1 2 3 1.......1 2 ... n...,即重复的1~1,1~2....1~n,给你一个\(k\),求第\(k(k<=10^{1 ...

  9. [CF1216E] Numerical Sequence hard version

    题目 The only difference between the easy and the hard versions is the maximum value of k. You are giv ...

随机推荐

  1. dotnet tool install:Failed to install tool package 'ZKEACMS.Publisher': Could not find a part of the path 'C:\Users\Christer\.dotnet\tools\.store\.stage\0qd2mqpa.m45\ZKEACMS.Publisher'

    问题 按照 ZKEACMS 运行命令 dotnet tool install --global ZKEACMS.Publisher 提示 Failed to install tool package ...

  2. Jenkins job docker 没有权限

    问题描述 基于docker使用jenkins 构建cicd,在执行docker build 的时候出现了权限的问题.具体报错如下 + REPOSITORY=10.0.0.100/library/wen ...

  3. 我们是如何做DevOps的?

    一.DevOps的理解 DevOps的概念理解 DevOps 的概念在软件开发行业中逐渐流行起来.越来越多的团队希望实现产品的敏捷开发,DevOps 使一切成为可能.有了 DevOps ,团队可以定期 ...

  4. Java 入门教程

    Java 入门教程 Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言. Java可运行于多个平台,如Windows, Mac OS,及其他多种UNIX版本的系统 ...

  5. SpringBoot整合分布式ZooKeeper和Dubbo

    ZooKeeper ZooKeeper是一个分布式的,开放远吗的分布式应用程序协调服务.它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. 服务提供者 ...

  6. TensorFlow从0到1之TensorFlow常用激活函数(19)

    每个神经元都必须有激活函数.它们为神经元提供了模拟复杂非线性数据集所必需的非线性特性.该函数取所有输入的加权和,进而生成一个输出信号.你可以把它看作输入和输出之间的转换.使用适当的激活函数,可以将输出 ...

  7. 关于MYSQL的查询时间段、删除数据、查询目标行的命令用法。

    Q1.第一次工作写命令时,写了一个把一个表的数据插入到另一个表中,运行时命令长时间处于执行状态. A.第一次处理数据库大量数据,长时间按运行属于正常现象,这与学校中的小数据不同. Q2.如何查询数据库 ...

  8. postman获得时间戳和md5加密的方法

    注意点:记得用postman.setGlobalVariable设置全局变量,不然{{strmd5}}这种变量取不到值

  9. java并发编程系列原理篇--JDK中的通信工具类Semaphore

    前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...

  10. 《MySQL技术内幕:InnoDB存储引擎》读书笔记

    一.Mysql体系结构和存储引擎 1. 概念:              数据库:物理操作系统文件或其他形式文件类型的集合.(是文件的集合,是依照某种数据模型组织起来并存放于二级存储器中的数据集合.) ...