DP POJ1019 递推&二分(思想)

Number Sequence

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 42304   Accepted: 12331

Description

A single positive integer i is given. Write a program to find the digit located in the position i in the sequence of number groups S1S2...Sk. Each group Sk consists of a sequence of positive integer numbers ranging from 1 to k, written one after another. 
For example, the first 80 digits of the sequence are as follows: 
11212312341234512345612345671234567812345678912345678910123456789101112345678910

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by one line for each test case. The line for a test case contains the single integer i (1 ≤ i ≤ 2147483647)

Output

There should be one output line per test case containing the digit located in the position i.

Sample Input

2
8
3

Sample Output

2
2

dp[i]存储到达i段时的总长,a[i]储存i段长度(emmm注释是另一种写法,清晰明了,还有第i位是几位这样子)

被安利了一个很棒的函数 log10() 可以非常方便地算出当前数字的位数 log10(i)+1

得到数i后,lower_bound函数二分到大于等于i的第一个数dp[pos],即数i在第pos段里;可以得到数i在pos段里是p=i-dp[pos-1]位;

得到p之后,lower_bound函数二分出大于等于p的第一个数a[q],即pos段p位是第q个数就是q中的一位;可以得到数i在pos段q数第m位m=p-a[q-1];

循环求出m位即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn=40000;

int main()
{
	int t;
	long long i;
	long long dp[maxn+10],/*s[maxn+10],*/a[maxn+10];	//dp当前j总长 s不同j分别多长 a当前位位数
	int ans;

	dp[0]=a[0]=0;
	for(long j=1;j<=maxn;++j){
		a[j]=a[j-1]+log10(j)+1;		//log10真是太机智了
		dp[j]=dp[j-1]+a[j];
	}

	scanf("%d",&t);
	while(t--){
		scanf("%lld",&i);
		long pos=lower_bound(dp,dp+maxn,i)-dp;
		long p=i-dp[pos-1];
		long q=lower_bound(a,a+maxn,p)-a;
		long m=p-a[q-1];
		long x=log10(q)+2-m;
		while(x){
			--x;
			ans=q%10;
			q=q/10;
		}
		printf("%d\n",ans);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/DADDY_HONG/article/details/81415796
今日推荐