轉載:
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
題目:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 24168 | Accepted: 6466 |
Description
For example, the first 80 digits of the sequence are as follows:
11212312341234512345612345671234567812345678912345678910123456789101112345678910
Input
Output
Sample Input
2 8 3
Sample Output
2 2
Source
解題思路:
首先建議數學底子不好的同學,暫時放一放這題,太過技巧性了,連理解都很困難
模擬分組,把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
- //Memory Time
- //476K 0MS
- #include<iostream>
- #include<math.h>
- using namespace std;
- const int size=31269;
- unsigned a[size]; //a[i] 表示第i組數字序列的長度
- unsigned s[size]; //s[i] 表示前i組數字序列的長度
- //第i組存放的數字序列爲 [1,i]的正整數,但第i組的長度不一定是i
- //例如數字13要被看做1和3兩個位,而不是一個整體
- /*打表,預先獲取第2147483647個位的序列分組情況*/
- void play_table(void)
- {
- a[1]=s[1]=1;
- for(int i=2;i<size;i++)
- {
- a[i]=a[i-1]+(int)log10((double)i)+1; //log10(i)+1 表示第i組數字列的長度 比 第i-1組 長的位數
- s[i]=s[i-1]+a[i]; //前i組的長度s[i] 等於 前i-1組的長度s[i-1] + 第i組的長度a[i]
- } //log()是重載函數,必須對int的i強制類型轉換,以確定參數類型
- return;
- }
- /*計算序列第n個位置上的數字*/
- int compute(int n)
- {
- int i=1;
- while(s[i]<n)
- i++; //確定整個數字序列的第n個位置出現在第i組
- int pos=n-s[i-1]; //pos爲 整個數字序列的第n個位置 在 第i組中的下標值
- int len=0;
- for(i=1;len<pos;i++) //從第1組開始遍歷第i前的每一個組,利用log10(i)+1遞推第i組的長度
- len+=(int)log10((double)i)+1; //len爲第i組(n所在的組)的長度
- return (i-1)/(int)pow((double)10,len-pos)%10;
- //之所以i-1,是因爲前面尋找第i組長度時,i++多執行了一次
- //i=i-1 此時i剛好等於第n位個置上的數 (數是整體,例如123一百二十三,i剛好等於123,但n指向的可能是1,2或3)
- //pos爲n指向的數字在第i組中的下標值
- //len爲第i組的長度
- //那麼len-pos就是第i組中pos位置後多餘的數字位數
- //則若要取出pos位上的數字,就要利用(i-1)/pow(10,len-pos)先刪除pos後多餘的數字
- //再對剩下的數字取模,就可以得到pos
- //例如要取出1234的2,那麼多餘的位數有2位:34。那麼用1234 / 10^2,得到12,再對12取模10,就得到2
- } //pow()是重載函數,必須對int的i強制類型轉換,以確定參數類型
- int main(void)
- {
- play_table();
- int test;
- cin>>test;
- while(test--)
- {
- int n;
- cin>>n;
- cout<<compute(n)<<endl;
- }
- return 0;
- }