1019:Number Sequence:详细题解

题目大意

题目传送门
求数字11212312341234512345612345671234567812345678912345678910123456789101112345678910111212345678910111213…的第i位是几?

思路分析

首先显然这个数列是有规律的,对于前组数据,分别为1,12,123,1234一个比前一个多一位,大于9,后一个比前一个多两位,大于99多三位,于是我们先打表看看到2147483647需要多少组数据,(显然我们不能把整个数列处理了,所以分组是一个不错的选择)

n[i]表示

	for (int i = 1; i < MAX; i++) {
		//这一位是几位数
		if (i > 9999)b = 5;//超过四位每次比前一组多5位 
		else if (i > 999)b = 4;
		else if (i > 99)b = 3;
		else if (i > 9)b = 2;
		else b = 1;
		n[i] = n[i - 1] + b;
		sn[i] = sn[i - 1] + n[i];
	}

可以看到第40000组不到就已经超过3000000000多位了(其实32000就够了),完全是够用了。
在这里插入图片描述
因此接下来,我们先要找到输入的数在第几组,然后找到在第几组的第几个数位,然后再找到这个他是这个数中的第几个数即可。

  • 找组:我们使用数组sn作为每个组位数的前缀和数组,ll index = lower_bound(sn, sn + MAX, b) - sn;即可找到大于等于输入数字b的第一组,也即目标所在组。
  • 找位:确定了b在第i组,那么b-sn[i-1]就是b在第i组的位置,我们使用以下循环来递增的找到b所处的数字jj的最后一位的位置len
for (j = 1; len < n1; j++)
	len += (int)log10(double(j)) + 1;
  • 此时我们有b的位置n1,也有·j的最后一位的位置len,那么len-n1就是数字j中处于b后面的位数,比如j=123,b=2多余的位数就是1,我们用 j / 10 ( l e n n 1 ) j/{10}^{(len-n1)} 就能把第i位放到个位数上,此时再对10取余即可。
#include<iostream>
#include<stack>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<cmath>
using namespace std;

#define MAX 40000
#define ll long long

ll n[MAX];//枚举每一组有多少位
ll sn[MAX]; // 每组位数的前缀和
string str;

//将k处理成字符串 比如 100:'100'
string rev(ll k) {
	string s, t;
	while (k > 0) {
		t += (k % 10) + '0';
		k /= 10;
	}
	for (int i = t.size() - 1; i >= 0; i--) {
		s += t[i];
	}
	return s;
}

int main() {
	ll N, b; cin >> N;
	for (int i = 1; i < MAX; i++) {
		//这一位是几位数
		if (i > 9999)b = 5;//超过四位每次比前一组多5位 
		else if (i > 999)b = 4;
		else if (i > 99)b = 3;
		else if (i > 9)b = 2;
		else b = 1;
		n[i] = n[i - 1] + b;
		sn[i] = sn[i - 1] + n[i];
	}

	for (int i = 0; i < N; i++) {
		cin >> b;
		ll index = lower_bound(sn, sn + MAX, b) - sn;//找到第一个组数大于等于b的元素,因此元素必在index-1组内
		ll num = n[index], n1 = b - sn[index - 1];
		ll len = 0, j;
		for (j = 1; len < n1; j++)
			len += (int)log10(double(j)) + 1;
		cout << (j - 1) / (int)pow((double)10, len - n1) % 10 << endl;
		//遍历完之后 j是这组中的一个数 j-1是b所在的那个数(数是整体,例如123一百二十三,i刚好等于123,但n指向的可能是1,2或3)
		//n1是b在第index组中的位置
		//len 是到数j结束的长度
		//len-n1是第index组中n1位置后面多余的位数
		//所以除以(int)pow((double)10, len - n1); 就是为了将后面的多余位删除
		//只要对剩下的数字取模即可
	}
}
发布了211 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csyifanZhang/article/details/105366358
今日推荐