传送门

这道题纯粹是考数学。编程复杂度不大(别看我写了一百多行其实有些是可以不必写的)。

计算位数不必用高精时刻存,不然可想而知时间复杂度之大。首先大家要知道一个数学公式 logn(a*b)=logn(a)+logn(b)至于证明翻数学书吧。而且,用log10(n)+1即可求出n的位数。

则2^p的位数=log10(2^p)+1=p*log10(2)+1。这样,我们算的时候就不必随时存着位数了。

但是,如果直接写高精和n次循环,时间复杂度依旧很高。所以我们就要用快速幂。幂的运算是初中内容,几个公式如下:n^a*n^b=n^(a+b),(n^a)^b=n^(a*b)。

所以,我们就可以将乘方的复杂度优化成O(logn)了。

代码

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream> using namespace std; const int MAXN = 2001; char c[MAXN]; inline char *read()
{
scanf("%s", c);
return c;
} struct Big_int
{
int s[MAXN], idx;
Big_int()
{
idx = 0;
memset(s, 0, sizeof(s));
}
inline void operator = (char *c)
{
idx = strlen(c);
for(int i = 0; i < idx; i++) s[i] = c[idx - i - 1] - '0';
}
inline void operator = (int x)
{
idx = 0;
memset(s, 0, sizeof(s));
if(!x) idx++;
while(x)
{
s[idx] = x % 10;
x /= 10;
idx++;
}
}
inline void print()
{
if(!idx) printf("0");
else for(int i = idx - 1; i >= 0; i--)
{
if(!((i + 1) % 50)) puts("");
printf("%d", s[i]);
}
puts("");
}
}; inline Big_int operator + (const Big_int x, const Big_int y)
{
Big_int ret;
ret.idx = max(x.idx, y.idx) + 1;
for(int i = 0; i < ret.idx; i++)
{
ret.s[i] += x.s[i] + y.s[i];
if(ret.s[i] >= 10)
ret.s[i + 1] += 1, ret.s[i] -= 10;
}
while(!ret.s[ret.idx - 1] && ret.idx > 1) ret.idx--;
return ret;
} inline bool operator < (const Big_int x, const Big_int y)
{
if(x.idx < y.idx) return 1;
if(x.idx > y.idx) return 0;
for(int i = x.idx - 1; i >= 0; i--)
if(x.s[i] ^ y.s[i])
return x.s[i] < y.s[i];
return 0;
} inline Big_int operator - (Big_int x, Big_int y)
{
Big_int ret;
if(x < y) swap(x, y);
ret.idx = x.idx;
for(int i = 0; i < ret.idx; i++)
{
if(x.s[i] < y.s[i])
{
x.s[i] += 10;
x.s[i + 1]--;
}
ret.s[i] = x.s[i] - y.s[i];
}
while(!ret.s[ret.idx - 1] && ret.idx > 1) ret.idx--;
return ret;
} inline Big_int operator * (const Big_int x, const Big_int y)
{
Big_int ret;
ret.idx = x.idx + y.idx;
for(int i = 0; i < x.idx; i++)
for(int j = 0; j < y.idx; j++)
{
ret.s[i + j] += x.s[i] * y.s[j];
ret.s[i + j + 1] += ret.s[i + j] / 10;
ret.s[i + j] %= 10;
}
while(!ret.s[ret.idx - 1] && ret.idx > 1) ret.idx--;
return ret;
} int p;
Big_int a, ans; int main()
{
int i, j, k, x, y;
scanf("%d", &p);
cout << floor(log(2) / log(10) * p + 1);
ans = 1;
a = 2;
while(p)
{
if(p & 1) ans = ans * a, ans.idx = min(ans.idx, 500);
a = a * a, a.idx = min(a.idx, 500);
p >>= 1;
}
a = 1;
ans = ans - a;
ans.idx = 500;
ans.print();
return 0;
}

  

[luoguP1045] 麦森数(快速幂 + 高精度)的更多相关文章

  1. 洛谷试炼场-简单数学问题-P1045 麦森数-高精度快速幂

    洛谷试炼场-简单数学问题 B--P1045 麦森数 Description 形如2^P−1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果PP是个素数,2^P-1 不一定也是素数.到19 ...

  2. [NOIP2003普及组]麦森数(快速幂+高精度)

    [NOIP2003普及组]麦森数(快速幂+高精度) Description 形如2^P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P-1不一定也是素数.到1998 ...

  3. TZOJ 4839 麦森数(模拟快速幂)

    描述 形如2^P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^P-1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=3021377,它有9 ...

  4. 【高精度乘法】NOIP2003麦森数

    题目描述 形如2^{P}-12P−1的素数称为麦森数,这时PP一定也是个素数.但反过来不一定,即如果PP是个素数,2^{P}-12P−1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的 ...

  5. NOIP200304麦森数

    试题描述 形如2P-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2P-1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=3021377,它有9 ...

  6. 【转】[NOIP2003普及组]麦森数

    来源:http://vivid.name/tech/mason.html 不得不纪念一下这道题,因为我今天一整天的时间都花到这道题上了.因为这道题,我学会了快速幂,学会了高精度乘高精度,学会了静态查错 ...

  7. vijosP1223麦森数

    vijosP1223麦森数 链接:https://vijos.org/p/1223 [思路] 快速幂+高精乘. 计算2^p-1可以快速幂的方法在O(logn)的时间内出解,限于数据范围我们需要用到高精 ...

  8. 洛谷 P1045 麦森数

    题目描述 形如2^{P}-1的素数称为麦森数,这时P一定也是个素数.但反过来不一定,即如果P是个素数,2^{P}-1不一定也是素数.到1998年底,人们已找到了37个麦森数.最大的一个是P=30213 ...

  9. 麦森数--NOIP2003

    题目描述 形如2P−12^{P}-12P−1 的素数称为麦森数,这时PPP 一定也是个素数.但反过来不一定,即如果PPP 是个素数,2P−12^{P}-12P−1 不一定也是素数.到1998年底,人们 ...

随机推荐

  1. java批处理、MySQL批处理

    e: cd MySQL\bin mysql -uroot -proot @pause MySQL批处理.bat e: cd JAVA\jdk1.8.0_77\bin javac Hello.java ...

  2. rsync常见错误

    rsync使用时的常见问题: 错误1: rsync: read error: Connection reset by peer (104) rsync error: error in rsync pr ...

  3. C# 判断是否移动设备

    /// <summary> /// 判断是否移动设备. /// </summary> /// <returns></returns> public st ...

  4. Node.js——基本服务开启

    标注模式 var http = require('http'); var server = http.createServer(); server.on('request', function (re ...

  5. ijkplayer seekTo回跳以前从指定位置播放解决办法

    相信在使用ijkplayer播放视频时候,大部分情况会遇到SEEKTO的问题,就是拖动后,不会从拖动结束的位置播放,而是大部分拖动后,会回跳一段时间,甚至从头开始播放. 官方称这 是正常的,因为视频拖 ...

  6. ubuntu15.04安装 RVM

    首先,请参考这篇文章 https://ruby-china.org/wiki/rvm-guide RVM 官方网站 https://rvm.io/ 1 由于现在很多网站都转向https链接,所以,根据 ...

  7. (转)淘淘商城系列——发布dubbo服务

    http://blog.csdn.net/yerenyuan_pku/article/details/72758639 Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入, ...

  8. C# 获取U盘ID序列号及U盘信息

    C# 获取U盘ID序列号及U盘信息 2011-05-20 上传大小:35KB c#VS2005U盘IDU盘信息   获取U盘ID序列号 VS2005编译通过,源码源自CSDN.已经测试好用. 可以获得 ...

  9. C++运行外部exe并判断exe返回值

    有三个API函数可以运行可执行文件WinExec.ShellExecute和CreateProcess.CreateProcess因为使用复杂,比较少用. WinExec主要运行EXE文件. ⑴ 函数 ...

  10. ubuntulinux 更改时区设置时间

    Linux/shell命令的实际应用——查看并修改系统时区 命令: www.2cto.com date -R //查询当前系统时间与默认时区 cp /usr/share/zoneinfo/Asia/S ...