POJ1019:Number Sequence

轉載:

http://www.cnblogs.com/kuangbin/archive/2011/07/21/2113279.html

http://blog.csdn.net/lyy289065406/article/details/6648504

http://poj.org/problem?id=1019

題目:

Number Sequence
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 24168   Accepted: 6466

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

Source

Tehran 2002, First Iran Nationwide Internet Programming Contest
 

解題思路:

首先建議數學底子不好的同學,暫時放一放這題,太過技巧性了,連理解都很困難

 

模擬分組,把1看做第1組,12看做第2組,123看做第3組……那麼第i組就是存放數字序列爲 [1,i]的正整數,但第i組的長度不一定是i

 

已知輸入查找第n個位的n的範圍爲(1 ≤ n ≤ 2147483647),那麼至少要有31268個組才能使得數字序列達到有第2147483647位

 

注意:2147483647剛好是int的正整數最大極限值( ),所以對於n用int定義就足矣。但是s[31268]存在超過2147483647的位數,因此要用unsigned 或long 之類的去定義s[]

 

詳細的解題思路請參照程序的註釋。

其中數學難點有2:

(int)log10((double)i)+1

(i-1)/(int)pow((double)10,len-pos)%10

非常技巧性的處理手法,其意義已在程序中標明

 

 

另外要注意的就是log()和pow()函數的使用

兩個都是重載函數,函數原型分別爲

double log(double)

float log(float)

double pow(double , double)

float pow(float ,float)

所以當傳參的類型不是double或float時,必須強制轉換爲其中一種類型,否則編譯出錯。一般建議用double

 

 

  1. //Memory Time   
  2. //476K    0MS   
  3.   
  4. #include<iostream>  
  5. #include<math.h>  
  6. using namespace std;  
  7.   
  8. const int size=31269;  
  9.   
  10. unsigned a[size];   //a[i] 表示第i組數字序列的長度  
  11. unsigned s[size];   //s[i] 表示前i組數字序列的長度  
  12.                      //第i組存放的數字序列爲 [1,i]的正整數,但第i組的長度不一定是i  
  13.                      //例如數字13要被看做1和3兩個位,而不是一個整體  
  14.   
  15. /*打表,預先獲取第2147483647個位的序列分組情況*/  
  16.   
  17. void play_table(void)  
  18. {  
  19.     a[1]=s[1]=1;  
  20.     for(int i=2;i<size;i++)  
  21.     {  
  22.         a[i]=a[i-1]+(int)log10((double)i)+1;  //log10(i)+1 表示第i組數字列的長度 比 第i-1組 長的位數  
  23.         s[i]=s[i-1]+a[i];      //前i組的長度s[i] 等於 前i-1組的長度s[i-1] + 第i組的長度a[i]  
  24.     }                          //log()是重載函數,必須對int的i強制類型轉換,以確定參數類型  
  25.     return;  
  26. }  
  27.   
  28. /*計算序列第n個位置上的數字*/  
  29.   
  30. int compute(int n)  
  31. {  
  32.     int i=1;  
  33.     while(s[i]<n)  
  34.         i++;    //確定整個數字序列的第n個位置出現在第i組  
  35.   
  36.     int pos=n-s[i-1];   //pos爲 整個數字序列的第n個位置 在 第i組中的下標值  
  37.   
  38.     int len=0;  
  39.     for(i=1;len<pos;i++)  //從第1組開始遍歷第i前的每一個組,利用log10(i)+1遞推第i組的長度  
  40.         len+=(int)log10((double)i)+1;  //len爲第i組(n所在的組)的長度  
  41.   
  42.     return (i-1)/(int)pow((double)10,len-pos)%10;    
  43.            //之所以i-1,是因爲前面尋找第i組長度時,i++多執行了一次  
  44.            //i=i-1 此時i剛好等於第n位個置上的數 (數是整體,例如123一百二十三,i剛好等於123,但n指向的可能是1,2或3)  
  45.            //pos爲n指向的數字在第i組中的下標值  
  46.            //len爲第i組的長度  
  47.            //那麼len-pos就是第i組中pos位置後多餘的數字位數  
  48.            //則若要取出pos位上的數字,就要利用(i-1)/pow(10,len-pos)先刪除pos後多餘的數字  
  49.            //再對剩下的數字取模,就可以得到pos  
  50.            //例如要取出1234的2,那麼多餘的位數有2位:34。那麼用1234 / 10^2,得到12,再對12取模10,就得到2  
  51.   
  52. }          //pow()是重載函數,必須對int的i強制類型轉換,以確定參數類型  
  53.   
  54. int main(void)  
  55. {  
  56.     play_table();  
  57.   
  58.     int test;  
  59.     cin>>test;  
  60.     while(test--)  
  61.     {  
  62.         int n;  
  63.         cin>>n;  
  64.         cout<<compute(n)<<endl;  
  65.     }  
  66.     return 0;  
  67. }  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章