来源:http://vivid.name/tech/mason.html

不得不纪念一下这道题,因为我今天一整天的时间都花到这道题上了。因为这道题,我学会了快速幂,学会了高精度乘高精度,学会了静态查错,学会了一个小小的变量的使用可能会导致整个程序挂掉。。

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

1279

Sample Output


看到这题第一感觉是简单,很容易就看懂了。然后,就没有然后了。不知道怎么做了,直接不断乘2肯定不仅超时而且超出范围。。明显用高精度。然后不知道用高精度乘这么多次会不会超时,于是想到快速幂。

想归想,这俩算法我都不会。于是问百度,看题解,看了好久,终于在上午似懂非懂地编出了快速幂(求a^b%m)。下午继续研究,终于又编出了高精度乘高精度的程序。这可完全是我自己蒙出来的,我没找到高精度乘高精度的例程。所以毫无悬念地在2^p,p上万时挂掉了。
就是因为自己想的高*高用了t、tt以及计算时处理进位,程序在次数较高的时候才挂掉了。这三个全部改掉才可以,只改掉任何一个仍然会挂。

本题分两问,第一问求位数,可以证明:当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).


PS:注意:原文这里描述是“故欲求x的位数只需求floor(log10(x)+1+0.5)(floor(x+0.5)是计算x的整数部分,这样可以避免浮点误差)。”

其实这个浮点数x加上0.5的最主要功能是四舍五入。这里多加0.5的话,会使得有些情况下的计算结果比正确结果多1.


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

while(p>)
{
if(p==)
{
    mul(ans,a);
    break;
  }
else
{
if(p%) mul(ans,a);
p/=;
mul(a,a);
}
}

话说我看了很多题解,都发现里面有一句“末位不要忘了减1”,一直百思不得其解。直到最后我才明白,原来是因为题目让算2^p-1。。还有,写这个程序的时候除了很多小错,比如递减的for循环写成了i++,x[i]*y[j]写成了x[i]*y[i]……这些都是编译器查不出来的,只有静态查错,也就是传说中的用眼睛自己看,才可以查到。从此以后我再也不敢完全依靠编译器了。

废话不多说,直接贴AC程序:

 #include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h> void mul(int x[],int y[])
{
/* x*y->x */
int tmp[]={},lx=,ly=,i,j,len;
memset(tmp,,sizeof(tmp));
while(x[lx]==&&lx>) lx--; //计算x首位位置
while(y[ly]==&&ly>) ly--; //计算y首位位置
len=lx+ly;
for(i=;i<=ly;i++)
for(j=;j<=lx;j++)
if(i+j-<=) tmp[i+j-]+=y[i]*x[j];
for(i=;i<=;i++) {tmp[i+]+=tmp[i]/; tmp[i]%=; if(i<&&tmp[i+]==) {len=i; break;}}
for(i=;i>;i--) x[i]=tmp[i];
}
int main()
{
long p;
int ans[]={},a[]={},i;
scanf("%ld",&p);
printf("%ld\n",(long)floor(p*log10()+));
/*快速幂求2^p,同时用高精度乘法*/
ans[]=; a[]=;
while(p>){
if(p==) {mul(ans,a); break;}
else{
if(p%) mul(ans,a);
p/=;
mul(a,a);}
}
ans[]-=;
for(i=;i>;i--) {printf("%d",ans[i]); if((i-)%==) printf("\n");}
//system("pause");
return ;
}

参考原文的代码,简化了一些地方:

 #include<stdio.h>
#include<math.h>
//#include<string.h>
void mul(int x[],int y[]);
int main()
{
long p;
int num=;
int ans[]={},a[]={},i;
freopen("Mason.in","r",stdin);
freopen("Mason.out","w",stdout);
scanf("%ld",&p);
num=(int)floor(p*log10()+);
printf("%d\n",num); /*快速幂求2^p,同时用高精度乘法*/
ans[]=; a[]=;
while(p>)
{
if(p&) //if(p%2==1)
mul(ans,a);
p=p>>; //p=p/2;
mul(a,a); //a*a -> a
}
ans[]-=; //这个地方其实直接减1会有bug。当ans[1]为0的时候是错误的结果。所以可以采用下面的方法减1。但是对这个题目而言,2^p-1必然是奇数,也即个位是不可能为0。(ans[1]不会为0.)
/*for(i=1;i<=500;i++)
{
if(ans[i]>0) {ans[i]--;break;}
}
for(;i>=1;i--) ans[i]=9;*/
for(i=;i>;i--) {printf("%d",ans[i]); if((i-)%==) printf("\n");}
printf("\n");
return ;
}
void mul(int x[],int y[])
{
/* x*y->x */
int tmp[]={},lx=,ly=,i,j,len; //tem[]一定要清零。
//memset(tmp,0,sizeof(tmp));
while(x[lx]==&&lx>) lx--; //计算x首位位置
while(y[ly]==&&ly>) ly--; //计算y首位位置
len=lx+ly;
for(i=;i<=ly;i++)
for(j=;j<=lx;j++)
if(i+j-<=) tmp[i+j-]+=y[i]*x[j]; //if语句是保证只保留500位
for(i=;i<=;i++)
{
tmp[i+]+=tmp[i]/; //把进位的值加到高位
tmp[i]%=;
/*if(i<500&&tmp[i+1]==0)
{len=i; break;}*/ //这个地方没理解其用意,似乎只是优化循环次数。但len没有使用的机会,所以干脆删除掉比较好。
}
for(i=;i>;i--) x[i]=tmp[i]; //把结果复制到x数组
}

【转】[NOIP2003普及组]麦森数的更多相关文章

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

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

  2. 洛谷 P1045 & [NOIP2003普及组] 麦森数

    题目链接 https://www.luogu.org/problemnew/show/P1045 题目大意 本题目的主要意思就是给定一个p,求2p-1的位数和后500位数. 解题思路 首先看一下数据范 ...

  3. P1045 [NOIP2003 普及组] 麦森数

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

  4. 【03NOIP普及组】麦森数(信息学奥赛一本通 1925)(洛谷 1045)

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

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

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

  6. 麦森数--NOIP2003

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

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

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

  8. [NOIP2003] 普及组

    乒乓球 模拟 /*By SilverN*/ #include<iostream> #include<algorithm> #include<cstring> #in ...

  9. 洛谷 P1045 麦森数

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

随机推荐

  1. [Camel Basics]

    Define routes: Either using Spring xml or Java DSL. Spring xml: <camelContext> <routeBuilde ...

  2. HDOJ-三部曲-1015-The Cow Lexicon

    The Cow Lexicon Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) To ...

  3. div+css文字垂直居中 解决左侧头像右侧姓名,姓名多换行后相对于头像仍居中显示

    在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...

  4. 第一个sprint与第二个sprint 阶段总结

    总体来说: 1.团队合作情况: 整个队伍配合得还算是不错的了,有些队员比较积极与主动,这是比较好的现象,因为一个队伍最终要的是活力与团结,至少我是这样认为的,如果一个队伍每个人都不干活,我想后果是不堪 ...

  5. ANTLR3完全参考指南读书笔记[04]

    前言 学习框架或第三方库的方法是什么 (1)少量的浏览manual或tutoral,只关注程序所需的特征,再完善其详细内容和特征的认识? (2)花大量的时间研究详细内容,再考虑程序实现? 这是个先有鸡 ...

  6. ES6 — 字符串String

    ES6对字符串新增了一些函数和操作规范.下面我们来看ES6中对字符串新加的特性. 1.模版字符串 (即用反引号定义的字符串) 传统的字符串拼接通过我们使用'+'号与变量连接.例如: let name= ...

  7. SQL注入测试平台 SQLol -1. 简介与安装

    最近下载了SQLol测试了一下,感觉挺好玩的,做一下记录. SQLol是一个可配置得SQL注入测试平台,它包含了一系列的挑战任务,让你在挑战中测试和学习SQL注入语句,SQLol还是比较有创意的项目. ...

  8. Android拍照保存图片内存大小

    图片拍摄的大小会随着硬件而变化,比如,像素高的相机拍出来的图片要比像素低的图片内存要大. 如此一来,针对机型可能调用camera app保存照片的时候,图片大小会不一样. 为了缩小图片大小,我们需要把 ...

  9. 计算2的N次方

    总时间限制:  1000ms 内存限制:  65536kB 描述 任意给定一个正整数N(N<=100),计算2的n次方的值. 输入 输入一个正整数N. 输出 输出2的N次方的值. 样例输入 5 ...

  10. hiho一下116周 网络流

    网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? ...