文章作者:姜南(Slyar) 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。
数学题,不难,倒是看解题报告学到了一个公式。
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:
11212312341234512345612345671234567812345678912345678910123456789101112345678910
Input
The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by one line for each test case. The line for a test case contains the single integer i (1 ≤ i ≤ 2147483647)
Output
There should be one output line per test case containing the digit located in the position i.
Sample Input
2
8
3
Sample Output
2
2
Slyar:给出一串那样的数字,很有规律的,总共有2147483647位,然后问你第 n 位上的数字是多少。一开始我理解错题意了,以为是问第 n 位的数是多少,WA了2次之后才发觉超过10以后的数字都不止1位了...悲剧
一开始做的复杂了,看了下解题报告才发现数字的位数可以用 log10((double)i) + 1 这个公式求出来,这样逐步求精就可以慢慢地求出结果了,具体方法我注释里写得很清楚。
直接一个一个求组,最后要16MS,如果之前把分组打表保存,就可以0MS过了。还有一个需要注意的就是边界,用int的话会溢出。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#include <iostream> #include <cmath> using namespace std; unsigned int a[31270], s[31270]; /* 打表 */ void reset() { int i; a[1] = 1; s[1] = 1; for(i = 2; i < 31270; i++) { /* 每一组数字都比上一组长 (int)log10((double)i) + 1 */ a[i] = a[i-1] + (int)log10((double)i) + 1; s[i] = s[i-1] + a[i]; } } /* 计算 */ int work(int n) { int i = 1; int length = 0; /* 找到 n 所在的组 */ while (s[i] < n) i++; /* n 在该组的下标 */ int pos = n - s[i-1]; /* length: n指向的数字的最后一位的下标 */ for (i = 1; length < pos; i++) { length += (int)log10((double)i) + 1; } /* 去掉所求位后面的数字然后取余 */ /* i: n指向的数字 + 1 */ return ((i-1) / (int)pow((double)10, length - pos)) % 10; } int main() { int t; unsigned int n; reset(); cin >> t; while(t--) { cin >> n; cout << work(n) << endl; } //system("pause"); return 0; } |