談?wù)劯呔扔?jì)算的應(yīng)用

哈嘍各位親愛(ài)的觀眾朋友們大家好!首先,或許是比較遲的祝各位圣誕快樂(lè)?。ㄎ覀儾欢歼^(guò)1024嗎?)近期,我發(fā)現(xiàn)我們班里不少人的麥森數(shù)這道題做的不是特別理想。所以今天我就以AC這道題的過(guò)來(lái)人的視角,出一期專(zhuān)欄,來(lái)探討一下麥森數(shù)的難,究竟難在何處。讓我們點(diǎn)開(kāi)下面的音樂(lè),開(kāi)啟今天的內(nèi)容吧?。ń袢找魳?lè)《The truth that you leave》)

題目描述
形如(2^P)-1的素?cái)?shù)稱(chēng)為麥森數(shù),這時(shí)P一定也是個(gè)素?cái)?shù)。但反過(guò)來(lái)不一定,即如果P是個(gè)素?cái)?shù),2^P-1不一定也是素?cái)?shù)。到1998年底,人們已找到了37個(gè)麥森數(shù)。最大的一個(gè)是P=3021377,它有909526位。麥森數(shù)有許多重要應(yīng)用,它與完全數(shù)密切相關(guān)。
任務(wù):從文件中輸入P(1000 < P < 3100000),計(jì)算2^P-1的位數(shù)和最后500位數(shù)字(用十進(jìn)制高精度數(shù)表示)。
輸入格式
文件中只包含一個(gè)整數(shù)P(1000 < P < 3100000)。
輸出格式
第一行:十進(jìn)制高精度數(shù)2^P-1的位數(shù);
第2-11行:十進(jìn)制高精度數(shù)2^P-1的最后500位數(shù)字(每行輸出50位,共輸出10行,不足500位時(shí)高位補(bǔ)0);
不必驗(yàn)證2^P-1與P是否為素?cái)?shù)。

題目的意思很簡(jiǎn)單,就是要求出2的n次方的10進(jìn)制后500位,以及這個(gè)數(shù)字一共有多少位。
根據(jù)一般人的想法,這個(gè)題的兩項(xiàng)輸出好像是有關(guān)聯(lián)的。但是事實(shí)證明,若想不超時(shí),這兩項(xiàng)輸出還真得分開(kāi)來(lái)處理!
我們先來(lái)看一下1st token——求出這個(gè)數(shù)的位數(shù)。這時(shí)候我們高中數(shù)學(xué)里的對(duì)數(shù)就派上用場(chǎng)了!

這里說(shuō)一下我個(gè)人用的一個(gè)不太完善的向下取整雙精度數(shù)輸出的方法:printf("%.0f",x-0.5);
然后我們進(jìn)行高精度的計(jì)算。這里我們不少人會(huì)稍微的在草稿紙上畫(huà)個(gè)圖來(lái)幫助自己思考一下。但這時(shí)候畫(huà)圖出錯(cuò)就很容易誤導(dǎo)大家了(別問(wèn)我為什么,我也是在這里出錯(cuò)的)

而且事實(shí)上,我們只用算后500位就行了。往后的任何位數(shù)都是不影響輸出結(jié)果的。這里面的原因需要大家聯(lián)想一下我們小學(xué)學(xué)的乘法豎式原理。高精度計(jì)算的方法我們?cè)谇懊嬉呀?jīng)講過(guò),在這里我們需要做一下改進(jìn),然后套在一個(gè)函數(shù)里隨時(shí)調(diào)用。
題解如下(我突然發(fā)現(xiàn)B站專(zhuān)欄里居然還有代碼塊這個(gè)東西,簡(jiǎn)直是程序員的福音?。?/p>
#include
#include
#include
#include
using namespace std;
int now[500];
int in;
void cr(){//高精度數(shù)*2
for(int a = 0;a<500;a++){
now[a] = now[a] * 2;
}for(int a = 499;a>0;a--){
now[a-1]+=now[a]/10;
now[a]=now[a]%10;
}
}
void fn(){//高精度數(shù)據(jù)平方
int ans[500];
memset(ans,0,sizeof ans);
int cw = 0;
for(int a = 499;a>=0;a--){
for(int b = 499;b>=0;b--){
if(cw<=b){
ans[b-cw]+=now[b]*now[a];
}
}
cw++;
}for(int a = 499;a>0;a--){
ans[a-1]+=ans[a]/10;
ans[a]=ans[a]%10;
}
ans[0]=ans[0]%10;
for(int a=0;a<500;a++){
now[a]=ans[a];
}
}
void sep(int fa){
if(fa==1){
cr();
return ;
}
else {
if(fa%2==0){
sep(fa/2);
fn();
}
else{
sep(fa/2);
fn();
sep(1);
}
}
}
int main(){//
memset(now,0,sizeof now);
cin >> in;
double cal;
cal = in;
printf("%.0f",(cal*0.301029995)+0.5);
cout << endl;
now[499]=1;
sep(in);
for(int a = 0;a<10;a++){
for(int b = 0;b<50;b++){
if((a*50)+b!=499)
cout <
好啦,今天的題解到這里也就結(jié)束了。喜歡的話(huà)記得——一鍵三連。這期閱讀超過(guò)50,我下期就再挑戰(zhàn)一次小木棍!

