思 路 来 源 于 思路来源于 思路来源于这里
令 a [ i ] 表 示 数 字 i 的 长 度 令a[i]表示数字i的长度 令a[i]表示数字i的长度
b [ i ] 是 a 数 组 的 前 缀 和 数 组 b[i]是a数组的前缀和数组 b[i]是a数组的前缀和数组
c [ i ] 是 b 数 组 的 前 缀 和 数 组 c[i]是b数组的前缀和数组 c[i]是b数组的前缀和数组
那 么 对 于 每 个 询 问 k , 去 数 组 二 分 一 个 最 大 的 m i d , 使 得 c [ m i d ] < k 那么对于每个询问k,去数组二分一个最大的mid,使得c[mid]<k 那么对于每个询问k,去数组二分一个最大的mid,使得c[mid]<k
k 减 去 c [ m i d ] , 这 就 是 剩 下 的 数 字 位 数 k减去c[mid],这就是剩下的数字位数 k减去c[mid],这就是剩下的数字位数
然 后 去 b 数 组 二 分 一 个 最 大 的 m i d , 使 得 b [ m i d ] < k 然后去b数组二分一个最大的mid,使得b[mid]<k 然后去b数组二分一个最大的mid,使得b[mid]<k
k − b [ m i d ] , 这 就 是 剩 下 的 数 字 位 数 , 且 一 定 在 m i d + 1 这 个 数 字 中 k-b[mid],这就是剩下的数字位数,且一定在mid+1这个数字中 k−b[mid],这就是剩下的数字位数,且一定在mid+1这个数字中
二分注意边界问题,因为0也是可以取得到的!!左边界最好设置为0!!(虽然我没有)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+10;
int q,k,a[maxn],b[maxn],c[maxn],last[maxn];
int isok(int mid,int k)
{
//数字mid的第k位
int w[6],top=0;
while( mid )
{
w[++top]=mid%10;
mid/=10;
}
if( k<0 )
{
while(1) cout << "NO!";
}
return w[top-k+1];
}
signed main()
{
for(int i=1;i<=100000;i++)
{
int num=0,x=i;
while( x )
{
num++;
x/=10;
}
a[i]=num,b[i]=b[i-1]+a[i],c[i]=c[i-1]+b[i];
}
cin >> q;
for(int i=1;i<=q;i++)
{
cin >> k;
int l=1,r=1e5,mid,now=0;
while( r>=l )
{
mid=l+r>>1;
if( c[mid]<k ) l=mid+1,now=mid;
else r=mid-1;
}
k-=c[now];//现在还剩了k个数字
l=1,r=1e5,now=0;
while( r>=l )
{
mid=l+r>>1;
if( b[mid]<k ) l=mid+1,now=mid;
else r=mid-1;
}
k-=b[now];
cout << isok(now+1,k) << endl;
}
}