麥森數(C++)
技術標籤:演算法
麥森數
Description
形如2P-1的素數稱為麥森數,這時P一定也是個素數。但反過來不一定,即如果P是個素數,2P-1不一定也是素數。到1998年底,人們已找到了37個麥森數。最大的一個是P=3021377,它有909526位。麥森數有許多重要應用,它與完全數密切相關。
任務:輸入P(1000<P<3100000),計算2P-1的位數和最後500位數字(用十進位制高精度數表示)。
Input
一個整數P(1000<P<3100000)。
Output
第一行:十進位制高精度數2P-1的位數;
第2-11行:十進位制高精度數2P-1的最後500位數字(每行輸出50位,共輸出10行,不足500位時高位補0);不必驗證2P-1與P是否為素數。
Sample Input
1279
Sample Output
386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
32958028878050869736186900714720710555703168729087
(寫個簡略的題解來向自己說明自己已經懂了)
這題的題意好理解,就是輸出2的p次方減一,但是資料太大就要超時,然後還只能用陣列寫。
先把程式碼貼出來:
#include<cstdio> #include<cstring> #include<cmath> typedef long long ll; int a[1005],b[505]; void ahh(ll x) { if(x==0)return ; ahh(x/2); for(int i=1;i<=500;i++) for(int j=1;j<=500;j++) { if(x%2==1)a[i+j-1]+=b[i]*b[j]*2; else a[i+j-1]+=b[i]*b[j]; } for(int i=1;i<=500;i++) { b[i]=a[i]%10; a[i+1]=a[i+1]+a[i]/10; } memset(a,0,sizeof(a)); } int main() { ll p; while(scanf("%lld",&p)!=EOF) { memset(b,0,sizeof(b)); b[1]=1; ahh(p); printf("%d\n",(int)(p*log10(2)+1)); b[1]-=1; for(int i=500;i>=1;i--) { if(i%50==0&&i!=500)printf("\n"); printf("%d",b[i]); } printf("\n"); } return 0; }
首先輸出一個位數,用log函式,是十進位制嘛,所以算出結果對10的對數就好了,很好理解,就比如,如果有一個m數的位數是n,那麼這個數一定大於等於10的n次方,小於等於10的(n+1)次方,那麼它的位數就是n=log10(m)+1
至於下面那個前500位的方陣,就拿樣例來說吧
2的1279次方,如果直接算1279此乘法就會超時,那麼就可以減少算的次數,2的1279次方=2的639次方x2的640次方,這樣就只用乘640次,但是又可以吧639次方分解為319和320…
思路大概就是這樣把p分解開來,每一次分解可以減少一半的運算次數
然後來看程式碼陣列a的作用是用來記錄每次相乘所得到的數,陣列b就是取末尾500位,所以陣列b的大小就是500,陣列a就是兩個陣列b相乘,就要1000
先第一個數b[1]=1,然後ahh(x)函式的作用就是算2的x次方,從樣例來看,要算2的1279次方可以先算2的639次方,然後繼續遞迴就是算319、159、79、39、19、9、4、2、1。
for(int i=1;i<=500;i++)
for(int j=1;j<=500;j++)
{
if(x%2==1)a[i+j-1]+=b[i]*b[j]*2;
else a[i+j-1]+=b[i]*b[j];
這一串程式碼的作用就是模擬兩個數的交叉相乘
而如果這時候算的x是偶數,那麼2的x次方的結果就是2的(x/2)次方乘2的(x/2)次方,如果x是奇數,2的x次方就是2的(x/2)次方乘2的(x/2)次方乘2,就像512=16x16x2,16=4x4…
然後再把所得結果進位,最後的500位給b陣列,重複遞迴。
最後輸出的時候b[1]記得-1,然後記得換行。
就這樣。