1. 程式人生 > >NOIP 2003 麥森數 COGS 41 高精快速冪+神奇的位數計算公式

NOIP 2003 麥森數 COGS 41 高精快速冪+神奇的位數計算公式

TAT,一開始讀錯題了,以為輸出的位數是超過500就預設輸出500的。還奇怪為什麼評論區裡大家都在說什麼位數計算公式,對數計算的換底公式啥的。
原來輸出的是原數的位數!

對於一個數k,它的位數是lg(k)+1。然而對於這道題得到一個可以放到cmath函式中的k是很困難的,題目要求的輸出也只是500位。但是題目給我們的是k = 2^n - 1中的n,那麼就可以用換底公式計算了,lg(k) = log2(k)/log2(10) = n/log2(10)。雖然減去一個1,不過對log的計算是沒有任何影響的。

之後寫個高精乘,用快速冪計算就好了,超過500位的部分忽略即可。

#include <cstdio>
#include <algorithm> #include <cstring> #include <cmath> #define P 100000 using namespace std; int n; struct BigInt{ long long h, a[200]; BigInt(){ h = 0; memset(a, 0, sizeof a); } void print(){ for(int i = 100; i; i--){ if(i%10 == 0 && i != 100
) putchar('\n'); printf("%.5lld", a[i]); } } BigInt operator * (BigInt k) const{ BigInt res; res.h = k.h+h+2; for(int i = 1; i <= h; i++) for(int j = 1; j <= k.h; j++){ res.a[i+j-1] += a[i] * k.a[j]; res.a[i+j] += res.a[i+j-1
] / P; res.a[i+j-1] %= P; } while(!res.a[res.h]) res.h--; res.h = min(res.h, (long long)100); return res; } }zero, res; BigInt pow(BigInt a, int i){ if(i == 0) return zero; if(i == 1) return a; BigInt k = pow(a, i>>1); if(i & 1) return k*k*a; return k*k; } int main() { scanf("%d", &n); printf("%d\n", 1+(int)(n/log2(10))); res.a[1] = 2; res.h = 1; res = pow(res, n); res.a[1]--; res.print(); return 0; }