nyist 413 && poj 1019 Number Sequence

题目链接:   nyist       poj

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:
112123123412345123456123456712345678123456789123456789101234567891011

题意:给出一串那样的数字,很有规律的,总共有2147483647位,然后问你第 n 位上的数字是多少。一开始我理解错题意了,以为是问第 n 位的数是多少,WA了2次之后才发觉超过10以后的数字都不止1位了...悲剧

一开始做的复杂了,后来才发现数字的位数可以用 log10((double)i) + 1 这个公式求出来,这样逐步求精就可以慢慢地求出结果了。

1 12 123 1234 12345 123456 1234567 12345678 123456789 12345678910 1234567891011 ......
按上面数列所示,我们把数列分为N段,第N-1段总是第N段的一个子集! 我们首先计算出最长的最大的最后一个段,假设第2147483647位处在第N段,我们则把这个第N段保存下来!

具体做法是用两个数组保存上面的数据,b[ ] 数组保存的是每段数的位数,b[i] 表示第i段位数,a[ ] 数组表示前面所有段的位数,a[i]表示前i段一共有多少位。解题的时候两次二分就可以了。比如查找第N位,先通过数组a[ ] 查找第N位在第几段,算出第几段的第几位,然后通过b[]数组确定第几位是多少。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
unsigned int a[32000],b[32000];
int main()
{
	unsigned int n,m,i,j,k;
	for(i=1,k=0;i<31270;i++)
	{
		b[i]=b[i-1]+(int)log10(double(i))+1;
		a[i]=a[i-1]+b[i];
	}
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d",&m);
		unsigned int mm=m-a[lower_bound(a,a+31270,m)-a-1];
		unsigned int *p=lower_bound(b,b+31270,mm);
		cout<<(p-b)/(int)pow((double)10,(int)(*p-mm))%10<<endl;;
	}
}        

 


还有一种方法是:a[]数组存储的信息不变,b[]数组存储的是序列12345678910111213......等各位位数对应数组数组的值,即b[1]=1, b[2]=2, b[3]=3, b[4]=4, b[5]=5, b[6]=6, b[7]=7, b[8]=8, b[9]=9,   b[10]=1,b[11]=0,    b[12]=1,b[13]=1,   b[14]=1,b[15]=1,   b[16]=1,b[17]=2,   b[18]=1,b[19]=3 .....等,由a数组查询计算出某段的第几位时(比如 i),直接对应输出就可以(b[i]); b数组一个循环就可;

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
long long  a[32000],b[200100];
int myitoa(int n,char *s) //itoa不是标准库函数,自己实现个
{ 
	return (n/10&&(*(s+myitoa(n/10,s)+1)=n%10+'0'))?(myitoa(n/10,s)+1):!(*s=n+'0');//这个函数功能就是把数字n转换成字符串而已,具体实现很简单, 不用像我这样写这么长一段话,只是当时好玩才这样写;
}
void ac()
{
	long long k=0,i,j;
	for(i=1;i<31500;i++)
	{
		k=k+(int)(log10(double(i)))+1;
		a[i]=a[i-1]+k;
	}
	char c[10];
	for(i=1,k=1;i<32000;i++)
	{
		memset(c,0,sizeof(c));
		myitoa(i,c);
		for(j=0;j<strlen(c);j++)
			b[k++]=c[j]-'0';
	}
}
int main()
{
	long long n,m;
	ac();
	scanf("%lld",&n);
	while(n--)
	{
		scanf("%lld",&m);
		long long *q=lower_bound(a,a+31400,m);
		cout<<b[m-a[q-a-1]]<<endl;
	}
	return 0;
}        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值