POJ 1019 - Number Sequence

题意:设字符串s1="1", s2="12", s3="123", ..., s13="12345678910111213", ...

求出串S = s1s2s3...s(k)...中的第x个数字(原题以i表示)。

最朴素的想法,直接生成S,最后直接取下标x的数字。这样做时间和空间都不允许(串长度可达2147483647)。

其实通过一些数学计算就可以做到:先算出第x个数字在哪个串s(k)中,并求出它在s(k)中的位置y。然后再求出在s(k) = 

1 2 3 4 5 6 ... k中,位置y对应的数m,这个m可能是多位数,所以还要求出在m中的位置z。最后位置z的数字即答案。

所以第一步求k和y,第二步求m和z,第三步得答案。

要求k,首先得知道各个串s(i)的长度len[i],怎么求?

把串s(i)写成以下形式,会更清晰:

  1

  2

  3

  :

 10

 11

 12

  :

100

101

102

  :

  :

[i]

长度就是个位数、十位数……的个数总和,用几个判断条件,很容易算出。

然后求串s(k)中的新下标y,用辅助数组start[i]记录s(i)起始点所在的位置,那么y = x - (start[k] - 1)

现在问题转变成求1 2 3 ... k 中的第y个数字,还是将其写成如下形式:

  1

  2

  3

  :

 10

 11

 12

  :

100

101 = m

102

  :

  :

[k]

我们先要找到第y个数字所对应的数m,

m满足:len[m-1] < y <= len[m]

最后求出在m中是第几个数字(z):

z = y - len[m-1]

比如z=2,则最终答案就是0.


题目给出x <= 2147483647,可以事先算好最大可能的k值(MAXK),然后对len、start打表。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

#define MAXK 31268

using namespace std;

int len[MAXK + 1];
int start[MAXK + 1];

void make_len()
{
	for (int k = 1; k <= MAXK; k++)
	{
		len[k] = 0;

		if (k >= 1)
			len[k] += k;
		if (k >= 10)
			len[k] += k - 9;
		if (k >= 100)
			len[k] += k - 99;
		if (k >= 1000)
			len[k] += k - 999;
		if (k >= 10000)
			len[k] += k - 9999;
	}
}

void make_start()
{
	start[1] = 1;
	for (int k = 2; k <= MAXK; k++)
		start[k] = start[k - 1] + len[k - 1];
}

int main()
{
	int T;
	cin >> T;

	make_len();
	make_start();

	while (T--)
	{
		int x, y, z, k, m;
		cin >> x;

		/* find k in S1S2S3... and y in S(k) */
		for (k = 1; k < MAXK; k++)
			if (x < start[k + 1]) break;
		y = x - (start[k] - 1);

		/* find m in 12345...k and z in m*/
		for (m = 1; m <= k; m++)
			if (y <= len[m]) break;
		z = y - len[m - 1];

		/* answer: the z-th number in m */
		char s[10];
		sprintf(s, "%d", m);
		cout << s[z - 1] << endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值