来源: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. Python入门(三,初级)

    一,函数调用 定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构. 这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行. 如下实例调用了pr ...

  2. __set()与__get() 魔术方法

    在面向对象编程的过程中,对于类当中的各个成员变量,都有不同的访问属性,比如公有的(public)属性,在类内部和类外部都可直接调用:而私有的(private)和受保护的(protected),在类外不 ...

  3. 【LeetCode】Best Time to Buy and Sell Stock IV

    Best Time to Buy and Sell Stock IV Say you have an array for which the ith element is the price of a ...

  4. 【LEETCODE OJ】Binary Tree Postorder Traversal

    Problem Link: http://oj.leetcode.com/problems/binary-tree-postorder-traversal/ The post-order-traver ...

  5. 关于Android Studio里的Gradle,你所需要知道的都在这里了

    Gradle介绍 Gradle是一个先进的build toolkit,可以方便的管理依赖包和定义自己的build逻辑.到底有多先进,Android Studio官方集成Gradle,Google还专门 ...

  6. XMLParser解析xml--内容源自网络(在静态库中不能用GDATA来解析,因为静态库不能加动态库)

    </Books> 从其文档结构我们可以看出,要定义一个Book实体类描述具体的书籍信息,其中用于存储的相关xml文档元素的实例变量与对应元素同名(本例:title.author.summa ...

  7. 学习笔记:APP切图那点事儿–详细介绍android和ios平台

    学习笔记:APP切图那点事儿–详细介绍android和ios平台 转载自:http://www.woofeng.cn/articles/168.html   版权归原作者所有 作者:亚茹有李 原文地址 ...

  8. BUAA 724 晴天小猪的神题(RMQ线段树)

    BUAA 724 晴天小猪的神题 题意:中文题,略 题目链接:http://acm.buaa.edu.cn/problem/724/ 思路:对于询问x,y是否在同一区间,可以转换成有没有存在一个区间它 ...

  9. SQL 存储过程中in

    存储过程中用in,如果将条件(1,2,3)这样的集合当成参数传进来的话是不能执行的,因为集合转成一个变量是出错 解决办法拼接SQL字符串传进来,后者在存过中拼接字符串都可以如: ALTER PROCE ...

  10. 转:去掉DataTable重复数据(程序示例比较)

    using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.T ...