luogu1045麦森数:高精度乘法+快速幂

本文探讨了在大规模数值下求解麦森数的两种有效方法:使用数学计算结合快速幂算法,以及通过高精度计算实现暴力求解。文章详细介绍了如何通过快速幂算法优化大数运算,同时提供了代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目连接

  • 该题是luogu试炼场的2-11:T2
  • 参考1:高精度*高精度(稍后更新)
  • 参考2:快速幂

题目大意

  1. 输入n,求 2n-1 的值;
  2. 输出有要求1:输出数位;
  3. 输出有要求2:后500位,分10行输出;

题目分析


朴素思维:高精度*低精度

  1. 暴力循环 n 次,2n-1应该能拿部分分;
  2. 提交发现拿了 50分,仁慈的数据~~
代码:
//luogu1045:麦森数1:50分 

//高精度*低精度 
//暴力拿部分分

#include <bits/stdc++.h>
using namespace std;

struct nod{int a[10000005],len;}a;
int n;

void cf()
{
	//乘法 
	for(int i=1;i<=a.len;i++) a.a[i]*=2;
	
	//进位 
	for(int i=1;i<=a.len;i++)
	{
		if(a.a[i]>=10)
		{
			a.a[i+1]+=a.a[i]/10;
			a.a[i]%=10;
			if(i==a.len) a.len++;
		}
	}	
}

int main()
{
	scanf("%d",&n);
	a.len=1;
	a.a[1]=1;
	
	for(int i=1;i<=n;i++)  
	{
		cf();//*2的计算 
	}
	
	//个位 -1 
	a.a[1]-=1; 
	//借位 
	for(int i=1;i<=a.len;i++)
	{
		if(a.a[i]<0)
		{
			a.a[i]=0;
			a.a[i+1]--;
		}
		else break;
	}
	
	printf("%d\n",a.len);//输出位数 
	
	n=10;
	while(n--)
	{
		for(int i=50;i>=1;i--) printf("%d",a.a[n*50+i]);
		printf("\n");
	}

  return 0;
}


解题思路:数学计算+快速幂

  1. 3w*90w的运算,暴力肯定是过不了的;
  2. 答案只要求输出500位,显然可能500位以上的,不需要具体运算;
  3. 就可以分两步走了:
  • 用某些(数学)方法算出答案的数位长度:2n 与数位的关系

    • 1 我们知道10x 的数位就是 x+1;
    • 2 设2n =10x
    • 3 x = log10 ( 2n )
    • 4 因为有公式: logn(a*b)=logn(a)+logn(b)
    • 5 由3 联立: x = log10 ( 2 * 2 * 2 * 2 * 2 * …* 2)
    • 6 由 4,5联立:x = log10(2)+log10(2)+log10(2)+ …+log10(2)
    • 7 所以: x = n * log10(2)
  • 进行500位的快速幂运算;

代码2:
  • 计算数位+快速幂优化
//luogu1045:麦森数 

//1:数学计算数位 
//2:高精度*高精度+快速幂 

#include <bits/stdc++.h>
using namespace std;

struct nod{int a[1005],len; nod(){memset(a,0,sizeof(a));}}a,b;
int n;

nod cf(nod x,nod y)//最多只做 500 位的运算 
{
	//初始化 
	nod z;
	if(x.len>500) x.len=500;
	if(y.len>500) y.len=500;
	z.len=x.len+y.len-1;
	
	//乘法 
	for(int i=1;i<=x.len;i++)
	{
		for(int j=1;j<=y.len;j++)
		{
			z.a[i+j-1]+=x.a[i]*y.a[j];
		}
	}

	//进位 
	for(int i=1;i<=z.len;i++)
	{
		if(z.a[i]>=10)
		{
			z.a[i+1]+=z.a[i]/10;
			z.a[i]%=10;
			if(i==z.len&&z.len<=500) z.len++;
		}
	}
	return z;	
}

int main()
{
	scanf("%d",&n);
	
	printf("%d\n",int(log10(2)*n+1));//数学算位数 
	
	a.len=1; a.a[1]=1;//存答案 
	b.len=1; b.a[1]=2;//寄存过程值 
	
	while(n>0)//快速幂 
	{
		if(n%2>0) a=cf(a,b);//幂是奇数:2^3=2*(2^2) 
		
		b=cf(b,b);//幂是偶数:2^8=(2^2)^4 
		
		n/=2;
	}

	//个位 -1 
	a.a[1]-=1; 
	for(int i=1;i<=a.len;i++)//借位
	{
		if(a.a[i]<0)
		{
			a.a[i]=0;
			a.a[i+1]--;
		}
		else break;
	}
	
	//输出 
	n=10;
	while(n--)
	{
		for(int i=50;i>=1;i--) printf("%d",a.a[n*50+i]);
		printf("\n");
	}

  return 0;
}


骨骼清奇的思路3


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值