【高精度】麥森數 NOIP 2003
阿新 • • 發佈:2019-02-13
[NOIP2003]麥森數
時間限制: 1 Sec 記憶體限制:64 MB
題目描述
形如2^p-1的素數稱為麥森數,這時p一定也是個素數。但反過來不一定,即如果p是個素數,2^p-1不一定也是素數。到1998年底,人們已找到了37個麥森數。最大的一個是p=3021377,它有909526位。麥森數有許多重要應用,它與完全數密切相關。現要求輸入p(1000< P < 3100000),計算2^p-1的位數和最後500位數字(用十進位制高精度數表示)。
輸入
第1行:1個整數p(1000
輸出
第1行:十進位制高精度數2^p-1的位數;第2..11行:十進位制高精度數2^p-1的最後500位數字(每行輸出50位,共輸出10行,不足500位時高位補0); 注意:不必驗證2^p-1與p是否為素數。
樣例輸入
(如果複製到控制檯無換行,可以先貼上到文字編輯器,再複製)
1279
樣例輸出
386 00000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000 00000000000000104079321946643990819252403273640855 38615262247266704805319112350403608059673360298012 23944173232418484242161395428100779138356624832346 49081399066056773207629241295093892203457731833496 61583550472959420547689811211693677147548478866962 50138443826029173234888531116082853841658502825560 46662248318909188018470682222031405210266984354887 32958028878050869736186900714720710555703168729087
剛開始看到這麼一大堆(tuÓ)輸出,其實我是拒絕的。
想了想,第一,高精度;第二,求p次冪要用快速冪(瞭解快速冪詳見點這裡!!)。
一、首先我們要知道怎麼存500位的數,那麼就存在一個結構體數組裡面,進行高精度乘法的時候,就可以想一想豎式是怎麼計算的。但是想一想豎式是從最低位開始乘起來的,所以我用的陣列是倒序存數,最後輸出只要倒回來輸出就行了。
這裡用到了過載運算子:
big operator *(big &ys)const {big ans; for(int i=1;i<=len;i++) for(int j=1;j<=ys.len;j++) { if(i+j-1>500) break;//如果位數>500,不用考慮 ans.A[i+j-1]+=A[i]*ys.A[j];//為什麼是i+j-1, //自己想想豎式計算 if(ans.A[i+j-1]>=10)//向後進位 { ans.A[i+j]+=ans.A[i+j-1]/10; ans.A[i+j-1]%=10; } } for(int i=500;i>=1;i--)//求位數 if(ans.A[i]!=0){ans.len=i;break;} return ans; }
二、進行冪運算的時候,要把p進行二進位制劃分(自己看上面的連結)。
三、程式碼如下:
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int p;
struct big
{
int A[501],len;//A存數,len存位數
big(){memset(A,0,sizeof A);len=0;}//清0
big operator *(big &ys)const//過載乘號
{big ans;
for(int i=1;i<=len;i++)
for(int j=1;j<=ys.len;j++)
{
if(i+j-1>500) break;
ans.A[i+j-1]+=A[i]*ys.A[j];
if(ans.A[i+j-1]>=10)
{
ans.A[i+j]+=ans.A[i+j-1]/10;
ans.A[i+j-1]%=10;
}
}
for(int i=500;i>=1;i--)
if(ans.A[i]!=0){ans.len=i;break;}
return ans;
}
}danwei,ans;
int main()
{
scanf("%d",&p);
danwei.A[1]=2;danwei.len=1;//danwei即使底數
ans.A[1]=1;ans.len=1;
printf("%d\n",int(p*log10(2))+1);
while(p)//快速冪
{
if(p&1) ans=ans*danwei;
p/=2;
danwei=danwei*danwei;
}
ans.A[1]--;//求的是2^p-1,所以最後--
for(int i=1;i<=10;i++)
{
for(int j=1;j<=50;j++)
printf("%d",ans.A[501-(i-1)*50-j]);//倒序輸出
printf("\n");
}
}