博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[NOIP2003普及组]麦森数(快速幂+高精度)
阅读量:6387 次
发布时间:2019-06-23

本文共 3108 字,大约阅读时间需要 10 分钟。

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

Description

形如2^P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2^P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。

任务:从文件中输入P(1000 < P < 3100000),计算2^P-1的位数和最后500位数字(用十进制高精度数表示)

Input

只包含一个整数P(1000 < P < 3100000)

Output

第一行:十进制高精度数2^P-1的位数。

第2-11行:十进制高精度数2^P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)
不必验证2^P-1与P是否为素数。

Sample Input

 

 

Sample Output

 

 

 

题目大意:计算2^P-1的位数和它的最后500位并输出。

1、计算位数:2^P-1的位数为[log10(2^P)]+1==[Plog10(2)]+1
2、计算最后500位:高精度预处理2^i,计算时将P分解成二进制形式,然后相乘,只保留500位
3、网站上的似乎和原题不太一样,原题要求每输出50位换行

 

倍增快速幂+高精(果然什么东西跟高精扯上就恶心了)

只保留最后500位,前面的直接卡掉

位数可以直接算出来,n进制数M的位数是log(n)M,那么log(10)2^p=p*log(10)2=p*(log(2)/log(10))

 

 

1、肯定需要高精度,毕竟500位

2、普通乘法肯定超时,乘法次数*位数

因为位数=plog(10)2=310W*log2

操作次数为=310W

所以普通乘法的复杂度为:n^2,这肯定要炸的不能在炸。 

如果是保留500位,那也是500*310W,也要超,所以这里一定要用到快速幂

 

 

 

本题分两问,第一问求位数,可以证明:当x有n位时,必有10^(n-1)<=x<10^n(如x有3位时必有100=10^2<=x<1000=10^3),取常用对数,n-1<=lgx<n,即lgx的整数部分是n-1,也就是说数x的位数是lg(x)的整数部分+1。故欲求x的位数只需求floor(log10(x)+1).

然后第二问是去掉了取模运算、用上高精度的快速幂:

 

 

1 #include 
2 using namespace std; 3 void mul(int x[],int y[]); 4 int main() 5 { 6 long p; 7 int num=0; 8 int ans[501]={
0},a[501]={
0},i; 9 freopen("mason.in","r",stdin); 10 freopen("mason.out","w",stdout);11 scanf("%ld",&p);12 //第一问ok 13 num=(int)floor(p*log10(2)+1);14 printf("%d\n",num);15 16 /*快速幂求2^p,同时用高精度乘法*/17 ans[1]=1; a[1]=2;18 while(p>0)19 {20 if(p&1) //if(p%2==1)21 mul(ans,a);22 p=p>>1; //p=p/2;23 mul(a,a); //a*a -> a24 }25 ans[1]-=1; //这个地方其实直接减1会有bug。当ans[1]为0的时候是错误的结果。所以可以采用下面的方法减1。但是对这个题目而言,2^p-1必然是奇数,也即个位是不可能为0。(ans[1]不会为0.) 26 /*for(i=1;i<=500;i++)27 {28 if(ans[i]>0) {ans[i]--;break;}29 }30 for(;i>=1;i--) ans[i]=9;*/31 for(i=500;i>0;i--) {printf("%d",ans[i]); if((i-1)%50==0) printf("\n");}32 printf("\n");33 return 0;34 }35 void mul(int x[],int y[])36 {37 /* x*y->x */38 int tmp[520]={
0},lx=500,ly=500,i,j,len; //tem[]一定要清零。39 //memset(tmp,0,sizeof(tmp));40 while(x[lx]==0&&lx>0) lx--; //计算x首位位置41 while(y[ly]==0&&ly>0) ly--; //计算y首位位置42 len=lx+ly;43 for(i=1;i<=ly;i++)44 for(j=1;j<=lx;j++)45 if(i+j-1<=500) tmp[i+j-1]+=y[i]*x[j]; //if语句是保证只保留500位 46 for(i=1;i<=500;i++) 47 {48 tmp[i+1]+=tmp[i]/10; //把进位的值加到高位 49 tmp[i]%=10;50 /*if(i<500&&tmp[i+1]==0)51 {len=i; break;}*/ //这个地方没理解其用意,似乎只是优化循环次数。但len没有使用的机会,所以干脆删除掉比较好。52 } 53 for(i=500;i>0;i--) x[i]=tmp[i]; //把结果复制到x数组 54 }

 

转载地址:http://iudha.baihongyu.com/

你可能感兴趣的文章
MVC解决更新冲突问题
查看>>
江西理工大学南昌校区cool code竞赛
查看>>
[LeetCode] Trim a Binary Search Tree 修剪一棵二叉搜索树
查看>>
Ubuntu SDL lib 安装
查看>>
Java 并发编程内部分享PPT分享
查看>>
关于discuz中禾金投票系统循环出现引导页的问题
查看>>
C#开源系统大汇总
查看>>
Linux服务器安全初始化自选安装Shell脚本
查看>>
PyCharm教程
查看>>
Python 简单的数据结构(一)
查看>>
谁说我们只会做工作流?做实验室管理系统我们也内行。
查看>>
yum安装开发库
查看>>
我的友情链接
查看>>
开源Python网络爬虫资料目录
查看>>
NSRunLoop Internals
查看>>
Hadoop2.4.1分布式安装
查看>>
PHP利用socket来实现POST数据
查看>>
Connection is read-only问题的产生原因与解决方法
查看>>
Proxmox VE 部署维护
查看>>
Linux软件包安装与卸载
查看>>