http://poj.org/problem?id=1019
有一串数字串,其规律为 1 12 123 1234 12345 123456 1234567 12345678 123456789 12345678910 1234567891011 123456789101112······k 输入位置n,计算这一串数字第n位是什么数字。
大致思路就是将这一串数按循环节分组,确定第n位数组出现在第几组,在那一组中有处在第几个位置,然后确定那位数是多少。 要确定这些东西,就需要预处理,用a[i]记录第i组序列的总位数,用s[i]记录前i组序列的总位数。这里记录一个重要的数学技巧,求一个数的位数可以用公式(int)log10((double)i)+1。 当确定第n位数在第x组序列时,我们需去除其后面多余的数,再取出该位数,这部分详见代码。
在这道题的DISCUSS中,看见一份用二分low_bound函数实现的代码,觉得也写得十分巧妙,因此也记录一下这种解法。
#include<cstdio> #include<algorithm> using namespace std; unsigned group[40000], sum[40000];//题目中给的最大数据一定不会超过40000组(粗略) int main() { int t, i, j, k, n, ans; char s[10]; scanf("%d", &t); group[0] = 0, sum[0] = 0; for( j=1; j<40000; j++) { group[j] += group[j-1] + 1 + (j/10 > 0) + (j/100 > 0) + (j/1000 > 0) + (j/10000 > 0);//递推计算第j组里有几个数字 sum[j] = sum[j-1] + group[j];//计算前j组数字个数之和 } while( t-- ) { scanf("%d", &i); k = lower_bound(sum, sum+40000, i) - sum;//计算第i个数位于哪个组 n = i - sum[k-1];//计算该数位于该组中的第几个位置 k = lower_bound(group, group+40000, n) - group;//找到位于哪个数中 n -= group[k-1];//该数的第几个位置 sprintf(s, "%d", k);//转化为字符形式,方便查找 ans = s[n-1] - '0'; printf("%d\n", ans); } return 0; }