NOIP 2003 麥森數 COGS 41 高精快速冪+神奇的位數計算公式
阿新 • • 發佈:2019-02-11
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;
}