CF1216E Numerical Sequence

题目链接

问题分析

奇奇怪怪的题。。。

首先思路达成一致,从大到小一步一步确定位置。

我们一边分析,一边讲算法。

112123123412345123456123456712345678123456789123456789101234567891011123456789101112

假设我们现在要找的是这个串中的倒数第二个位置(就是1),我们可以这样做:

首先,我们想象着把串分开,变成

1
12
123
1234
12345
123456
1234567
12345678
123456789
12345678910
1234567891011
123456789101112

由于我们发现, 最后一个数字 位数相同 的串 的长度 是一个等差数列,可以方便地求得数列和。所以我们可以枚举 所求位置所在串 的 最后一个数字 的 位数。

在这个例子中,我们先枚举 最后一个数字 的 位数 为\(1\),可以算得这样的串的总长是 \((1+9)*9/2\)。发现不到所求位置,于是把这些串扔掉,顺便所求位置减\(45\)

12345678910
1234567891011
123456789101112

然后枚举 最后一个数字 的 位数 为\(2\),可以算得这样串的总长是 \((11+(9+2*90))*90/2\)大于所求位置。

所以我们知道了 所求位置 所在串 的 最后一个数 的 位数 是 \(2\)

然后同样的,根据这个等差数列,我们可以二分求得 所求位置 所在串 的 最后一个数 是多少。

这个例子中,最后锁定在串

123456789101112

然后……

我们可以重复上面的操作,把串分成

1 2 3 4 5 6 7 8 9 10 11 12

然后重复上面的第一步操作确定 所求位置 所在数 的 位数。只不过这次长度数列不再是等差数列,而是值等于数字位数的常数列。

在这个例子中,我们删掉了长度为\(1\)的,留下

10 11 12

然后可以直接算出 所求位置在 12 里。然后问题就解决了!

参考程序

#include <bits/stdc++.h>
#define LL long long
using namespace std;

void Work() {
	LL n;
	scanf( "%lld", &n );
	LL LastLen = 0, Len, Count;
	for( Len = 1; ; ++Len ) {
		Count = 9;
		for( LL i = 1; i < Len; ++i ) 
			Count = Count * 10;
		LL Sum = ( LastLen + Len + LastLen + Count * Len ) * Count / 2;
		if( n <= Sum ) break;
		n -= Sum;
		LastLen += Count * Len;
	}
	LL Left = 1, Right = Count, Mid, Ans;
	while( Left <= Right ) {
		Mid = ( Left + Right ) >> 1;
		LL Sum = ( LastLen + Len + LastLen + Mid * Len ) * Mid / 2;
		if( Sum >= n ) {
			Ans = Mid;
			Right = Mid - 1;
		} else Left = Mid + 1;
	}
	--Ans;
	n -= ( LastLen + Len + LastLen + Ans * Len ) * Ans / 2;
	++Ans;
	for( Len = 1; ; ++Len ) {
		Count = 9;
		for( LL i = 1; i < Len; ++i ) 
			Count = Count * 10;
		LL Sum = Count * Len;
		if( Sum >= n ) break;
		n -= Sum;
	}
	LL Num = ( n + Len - 1 ) / Len;
	n = n - ( Num - 1 ) * Len;
	LL T = 1;
	for( LL i = 1; i < Len; ++i ) T = T * 10;
	Num = T + Num - 1;
	T = Len - n + 1;
	for( LL i = 1; i < T; ++i ) Num = Num / 10;
	printf( "%lld\n", Num % 10 );
	return;
}

int main() {
	LL Query;
	scanf( "%lld", &Query );
	for( LL i = 1; i <= Query; ++i ) Work();
	return 0;
}
posted @ 2019-09-23 20:08  chy_2003  阅读(374)  评论(0编辑  收藏  举报