【NOIP2003】麦森数
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1045
这道题的难点在于两个,一是求出2N-1的位数,而是求出2N-1的后500位。
实际上第二个比较容易实现,写个高精度外加快速幂就可以了。由于最后结果位数比较大,即使是效率很高的快速幂也会超时,所以我们要另想办法求2N-1的位数。我们发现,2N的一位不可能是0,2N-1和2N的位数实际上是一样的。而且,若某个数是10K,那么这个数的位数是K+1。把2N写成(10lg2)N,求出lg2*N+1就是最后答案的位数。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 5 const int maxn = 1e6 + 5; 6 7 int p, ans[maxn], x[maxn], al, xl, c[maxn], cl; 8 9 inline void mul(int a[], int b[], int& al, int bl) { 10 memset(c, 0, sizeof(c)); 11 cl = 1; 12 for (int i = 1; i <= al; ++i) 13 for (int j = 1; j <= bl; ++j) { 14 if (i + j - 1 > 500) break; 15 c[i + j - 1] += a[i] * b[j]; 16 if (c[i + j - 1] > 9) { 17 c[i + j] += c[i + j - 1] / 10; 18 c[i + j - 1] %= 10; 19 } 20 } 21 cl = al + bl; 22 while (!c[cl] && cl > 0) --cl; 23 for (int i = 1; i <= cl; ++i) a[i] = c[i]; 24 al = cl; 25 } 26 27 inline void quickpow() { 28 ans[1] = 1, al = 1; 29 x[1] = 2, xl = 1; 30 while (p) { 31 if (p & 1) mul(ans, x, al, xl); 32 mul(x, x, xl, xl); 33 p >>= 1; 34 } 35 } 36 37 int main() { 38 scanf("%d", &p); 39 printf("%d\n", (int)(log10(2) * p + 1)); 40 quickpow(); 41 --ans[1]; 42 for (int i = 1; i < al; ++i) 43 if (ans[i] < 0) --ans[i + 1], ans[i] += 10; 44 for (int i = 10; i >= 1; --i) { 45 if (i != 10) putchar('\n'); 46 for (int j = 50; j >= 1; --j) 47 printf("%d", ans[(i - 1) * 50 + j] ? ans[(i - 1) * 50 + j] : 0); 48 } 49 return 0; 50 }