9.AcWing792.高精度乘法(AcWing算法基础课二刷)

关键词:高精度乘法(高精*单精)、高精度乘法(高精*高精)、vector(容器)、压位

地位:算法竞赛普遍涉及,在笔试、面试是一个比较重要的考点。

高精度整数的储存方法在高精度加法已经介绍过了,高精度的加减乘除有很多相同之处。

 高精度加法的链接就在下方,还没了解高精度的读者可以先了解这篇文章:

7.AcWing791.高精度加法(AcWing算法基础课二刷)_浩子诚的博客-CSDN博客

高精度乘法是算法竞赛出现次数最多的高精度。组合数、排列数、一些动态规划都涉及到乘法,而且有些题目不会让选手模1e9+7。这类题目就需要让读者手写高精度乘法。高精度乘法的原理也不难,不过可惜y总只讲了高精*单精的情况,下文会补充高精*高精的情况。

先来探讨高精*单精的情况:

高精度乘法的时间复杂度约为O\left ( n \right ),其中n为高精度的位数。

把单精度B看作一个整体之后(与常规的竖式乘法不太相同),之后从高精度A的个位开始与B相乘,设t是当前需要进位的数字(初始为0),则第i位存储(A_{i}*b+t) mod 10,即该数字的个位(y总在此笔误),直到乘完为止。如果t不为0,则逐位存储,最终获得一个高精度数字。

下图举出了一个通俗易懂的例子:

假设高精度A为123,单精度B为12,则步骤是这样的:

①.3*12=36,vector存储6,t为3,个位计算完成;

②.2*12=24,24+3=27,vector存储7,t为2,十位计算完成;

③.1*12=12,12+2=14,vector存储4,t为1,百位计算完成;

A与B相乘的过程结束。之后t不为0,t需要从个位开始存储到vector容器,存储1。

所以答案是1476,大家可以用计算器或自己列竖式验证。

其实上述的过程可以描述成下面几个步骤:

①.A的某一位与B相乘,之后加上t的个位(进位);

②.将结果的个位存进vector容器,进位t除以10,除以10之后t的个位是下一步的进位;

③.遍历完A后,如果t不为0,将t逐位存进vector容器。

不过有一点需要注意:如果A或B为0,vector容器就有可能出现储存一连串0的情况,此时只需要特判即可,不需要删除前导零(这种题目一般很少)

下面上基于y总算法实现的模板代码,看了你会更深一步理解:

#include<iostream>
#include<vector>
using namespace std;
//高精*单精
vector<int> mul(vector<int> &a,int b)
{
    int t=0;
    vector<int> ans;
    // ||t的意思是如果t不为0,即t为true的状态
    for(int i=0;i<a.size()||t;i++)
    {
        //注意要判断有没有乘完
        if(i<a.size()) t+=a[i]*b;
        //插入t的个位
        ans.push_back(t%10);
        t/=10;
    }
    return ans;
}
int main()
{
    string A;
    int b;
    vector<int> a,c;
    cin>>A>>b;
    if(b==0) cout<<0;//特判乘0情况
    else
    {
        //存储和输出
        for(int i=A.size()-1;i>=0;i--)
        a.push_back(A[i]-'0');
        c=mul(a,b);
        for(int i=c.size()-1;i>=0;i--)
        cout<<c[i];
    }
    return 0;
}

我们已经初步了解高精*单精的高精度乘法,接下来要讲的是高精*高精的高精度乘法。笔者将配合这道题讲解高精*高精的乘法与压位;(高精*单精的乘法不容易TLE)

P1303 A*B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<cstring>
using namespace std;
//注意压位后的结果可能会爆int 所以开long long
long long c[5000];
long long a[2010],b[2010];
char A[2010],B[2010];
int main()
{
	scanf("%s%s",A,B);
	int j=0,alen,blen;
//压4位操作,使用比较暴力的方法
	for(int i=strlen(A)-1;i>=0;i-=4,j++) 
	{
		if(i>=3)
		{
			a[j]=(A[i-3]-'0')*1000+(A[i-2]-'0')*100+(A[i-1]-'0')*10+(A[i]-'0');
		}
		else
		{
			if(i==2) a[j]=(A[i-2]-'0')*100+(A[i-1]-'0')*10+(A[i]-'0');
			if(i==1) a[j]=(A[i-1]-'0')*10+(A[i]-'0');
			if(i==0) a[j]=(A[i]-'0');
		}
	}
	alen=j;//j为A压位后的最高位+1
	j=0;
//也给B压位
	for(int i=strlen(B)-1;i>=0;i-=4,j++) 
	{
		if(i>=3)
		{
			b[j]=(B[i-3]-'0')*1000+(B[i-2]-'0')*100+(B[i-1]-'0')*10+(B[i]-'0');
		}
		else
		{
			if(i==2) b[j]=(B[i-2]-'0')*100+(B[i-1]-'0')*10+(B[i]-'0');
			if(i==1) b[j]=(B[i-1]-'0')*10+(B[i]-'0');
			if(i==0) b[j]=(B[i]-'0');
		}
	}
	blen=j;
//i位*j位=(i+j)位,就例如个位*十位=百位
	for(int i=0;i<alen;i++)
	for(int j=0;j<blen;j++)
	{
		c[i+j]+=a[i]*b[j];
	}
//clen的最大可能长度
	int clen=alen+blen+1;
	for(int i=0;i<=clen;i++)
	{
    //如果某一位超过4位就对10000取模 然后进位加给上一位
		if(c[i]>9999)
		{
			c[i+1]+=c[i]/10000;
			c[i]%=10000;
		}
	}
    //删除前导零操作
	while(c[clen]==0&&clen!=0) clen--;
    //输出最高位
	printf("%d",c[clen]);
    //其他位要打印前导零
	for(int i=clen-1;i>=0;i--) printf("%04d",c[i]);
	return 0;
}

这是高精*高精的高精度乘法,时间复杂度O\left ( n^2 \right ),压位后会进行常数优化,减少超时的几率。

参考链接/文献:

Ⅰ.AcWing——算法基础课,2019,闫学灿 活动 - AcWing

Ⅱ.AcWing793.高精度乘法 793. 高精度乘法 - AcWing题库

感谢您的支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值