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

思路来源于 这里

a [ i ] i 令a[i]表示数字i的长度

b [ i ] a b[i]是a数组的前缀和数组

c [ i ] b c[i]是b数组的前缀和数组

k , m i d , 使 c [ m i d ] < k 那么对于每个询问k,去数组二分一个最大的mid,使得c[mid]<k

k c [ m i d ] , k减去c[mid],这就是剩下的数字位数

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

k b [ m i d ] , , m i d + 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;
	}
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/107727422