信息学奥赛一本通 1925:【03NOIP普及组】麦森数 | OpenJudge NOI 4.4 1708:麦森数 | 洛谷 P1045 [NOIP2003 普及组] 麦森数
【題目鏈接】
ybt 1925:【03NOIP普及組】麥森數
OpenJudge NOI 4.4 1708:麥森數
洛谷 P1045 [NOIP2003 普及組] 麥森數
【題目考點】
1. 高精度
2. 求一個數字位數
設正整數x的的位數為n,那么有:n=?lgx?+1n = \lfloor lgx \rfloor + 1n=?lgx?+1(lgxlgxlgx:以10為底x的對數)
證明:正整數x和它的位數n之間滿足:n=?lgx?+1n = \lfloor lgx \rfloor + 1n=?lgx?+1
已知:10n?1≤x<10n10^{n-1}\le x <10^n10n?1≤x<10n(舉例:10≤15<100,100≤168<100010\le 15<100, 100\le168<100010≤15<100,100≤168<1000)
對不等式各邊取以10為底的對數,有:n?1≤lgx<nn-1\le lgx < nn?1≤lgx<n
所以有:n?1=?lgx?n-1 = \lfloor lgx \rfloorn?1=?lgx?
所以:n=?lgx?+1n = \lfloor lgx \rfloor + 1n=?lgx?+1
【解題思路】
- 求2p?12^p-12p?1的位數
x-1的位數與x的位數只有在x為10n10^n10n(n為正整數)的情況下才不同,其它情況下一定相同。
2p2^p2p一定不是10n10^n10n,所以2p?12^p-12p?1的位數和2p2^p2p的位數相同。
根據公式n=?lgx?+1n = \lfloor lgx \rfloor + 1n=?lgx?+1,求出2p2^p2p的位數為:
n=?lg2p?+1=?p?lg2?+1n = \lfloor lg2^p \rfloor + 1=\lfloor p\cdot lg2 \rfloor + 1n=?lg2p?+1=?p?lg2?+1 - 求2p?12^p-12p?1的后500位
當p>1時2p2^p2p的個位只可能是2,4,6或8,所以2p2^p2p與2p?12^p-12p?1只是個位不同。可以先求出2p2^p2p的后500位的數字,然后個位再減1即為結果。
要求出2p2^p2p的后500位的數字,需要使用高精度計算。高精度數字只設為500位,如果向更高位進位,則忽略(因為更高位的數值無法影響最低的500位)。
求2p2^p2p的后500位有兩種方法:
解法1:每次乘以2x2^x2x
p的最大值達到大約3?1063*10^63?106,每次進行500位的運算,乘以500后,約為1.5?1091.5*10^91.5?109,一定會超時的。
如果每次乘2,需要乘m次;那么如果每次乘4,只需要乘m/2次,每次乘8,只需要乘m/3次…每次乘2x2^x2x,共需要乘m/x次m/x次m/x次
如果x取20,那么需要乘3?106/20=1.5?1053*10^6/20=1.5*10^53?106/20=1.5?105,再乘以500,總運算次數為7.5?1077.5*10^77.5?107,不會超時了。
先做p%x次乘2,再做p/x次乘2x2^x2x,即可求出2p2^p2p,使用高精乘低精。
解法2:快速冪
快速冪中要求解的數字和基數都達到高精度,所以要寫高精乘高精。
快速冪進行中,要對數字或基數模500,因為只有數字或基數的末500位影響結果的末500位。
【題解代碼】
解法1:每次乘以2x2^x2x
#include <bits/stdc++.h> using namespace std; #define N 1005 #define M 500 void MultiAndMod(int a[], int b)// a=a*b取末M位 高精乘低精 {int c = 0, i;//進位 for(i = 1; i <= a[0]; ++i){a[i] = a[i] * b + c;c = a[i] / 10;a[i] %= 10;}while(c > 0){a[i] = c % 10;c /= 10;i++;}while(a[i] == 0 && i > 1)i--;a[0] = i;if(a[0] > M)//限制高精度數字a的位數,忽略高于500的數字忽a[0] = M; } int main() {int p, a[N] = {}, r, m;//a:數字數組 r:剩下需要乘以2的次數 cin >> p;cout << floor(p * log10(2)) + 1 << endl;//求位數a[0] = a[1] = 1;//將a設為1m = p / 20;//m:a乘以2^20的次數r = p % 20;//r:a乘以2的次數 for(int i = 1; i <= r; ++i)MultiAndMod(a, 2);for(int i = 1; i <= m; ++i)MultiAndMod(a, 1048576);//1048576:是2^20 a[1]--;//減1 for(int i = 500; i >= 50; i -= 50)//i:起始位數 {for(int j = i; j > i-50; --j)cout << a[j];cout << endl;} return 0; }解法2:快速冪
#include <bits/stdc++.h> using namespace std; #define N 1005 #define M 500 void MultAndMod(int a[], int b[])//高精乘高精 a = a*b%M {int r[N] = {}, ri;for(int i = 1; i <= a[0]; ++i){int c = 0;//進位 for(int j = 1; j <= b[0]; ++j){r[i+j-1] += a[i]*b[j] + c;c = r[i+j-1] / 10;r[i+j-1] %= 10;}r[i+b[0]] += c;}ri = a[0] + b[0];while(r[ri] == 0 && ri > 1)ri--;r[0] = ri;if(r[0] > M)//只取末500位r[0] = M;for(int i = 0; i <= r[0]; ++i)//結果r賦值給aa[i] = r[i]; } int main() {int p, a[N] = {1,1}, b[N] = {1,2};//a,b是數字數組。a:結果,初值為1 b:基數,初值為2 cin >> p;//指數cout << floor(p * log10(2)) + 1 << endl;//求位數while(p > 0)//快速冪{if(p % 2 == 1)MultAndMod(a, b);//a = a*b%MMultAndMod(b, b);//b = b*b%Mp /= 2; }a[1]--;//減1 for(int i = 500; i >= 50; i -= 50)//輸出解 i:起始位數 {for(int j = i; j > i-50; --j)//輸出50個數 cout << a[j];cout << endl;} return 0; }總結
以上是生活随笔為你收集整理的信息学奥赛一本通 1925:【03NOIP普及组】麦森数 | OpenJudge NOI 4.4 1708:麦森数 | 洛谷 P1045 [NOIP2003 普及组] 麦森数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息学奥赛一本通 2042:【例5.10
- 下一篇: linux查看删除init内容,linu