E1. Numerical Sequence (easy version)[前缀和优化]

思 路 来 源 于 思路来源于 这里

令 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],这就是剩下的数字位数 kc[mid],

然 后 去 b 数 组 二 分 一 个 最 大 的 m i d , 使 得 b [ m i d ] < k 然后去b数组二分一个最大的mid,使得b[mid]<k bmid,使b[mid]<k

k − b [ m i d ] , 这 就 是 剩 下 的 数 字 位 数 , 且 一 定 在 m i d + 1 这 个 数 字 中 k-b[mid],这就是剩下的数字位数,且一定在mid+1这个数字中 kb[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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值