C - 咕咕东的奇妙序列

题意介绍

一个序列:
112123123412345123456…即第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所有数字,第i部分总是包含1至i之间的所有数字。求第k项数字是多少,注意第56项的数字为0.

题意分析

由分析可知:
第一部分到第九部分相邻部分的数字长度加一;
第十部分到第九十九部分相邻部分的数字长度加二;
第一百部分到第九百九十九部分相邻部分数字长度加三;
余下的依次类推。
由此可知,如果把第一部分到第九部分看作是一段,每一段的数字长度组成一个序列,即{1,2,3,4,5,6,7,8,9},则这个序列为一个等差序列,我们可以求出来这一段数字的总长度,往后可以以此类推。等差序列求和公式为 s=a0+n*(n-1)*d/2,其中a0为等差序列的首项,n为序列元素个数,d为公差。
在这道题中,先利用二分找到ans,前ans部分总位数小于或等于k,求出前ans部分总位数,第ans+1部分第(k减去前ans部分总位数)位就为答案。

通过代码

#include<iostream>
using namespace std;


int q;
long long k;

long long getSum(long long a) {
	long long end = 1, start = 1, d = 0, n = 0;
	long long sum = 0;
	while (true) {
		end = end * 10;//每一段的结尾数字
		d++;
		n = end - end / 10;

		if (a > end-1) {
			sum += start * n + n * (n - 1)*d / 2;
			start += (n - 1)*d + d + 1;
		}
		else {
			n = a - end / 10+1;
			sum += start * n + n * (n - 1)*d / 2;
			break;
		}

	}
	return sum;
}

int solve(long long k) {
	int l = 0, r = 1e9, mid = 0, ans;
	while (l <= r) {
		mid = (l + r) / 2;
		long long sum = getSum(mid);
		if (sum < k) {
			ans = mid;
			l = mid + 1;
		}
		else
			r = mid - 1;
	}
	return ans;
}

void getNum(long long k) {
	long long end = 1,  d = 0, n = 0, sum = 0,pos=0;
	while (k) {
		end = end * 10;
		n = end - end / 10;
		d++;
		if (k > n*d) {
			sum += n;
			k -= n * d;
		}
		else {
			sum += k / d;
			pos = k % d;
			break;
		}
	}
	if (pos == 0) cout << sum % 10 << endl;
	else {
		sum += 1;
		while (d != pos) {
			d--;
			sum /= 10;
		}
		cout << sum % 10 << endl;
	}
}
int main() {
	cin >> q;
	while (q--) {
		cin >> k;

		int ans = solve(k);
		k = k - getSum(ans);
		getNum(k);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值