codevs P3117 高精度练习之乘法

一万(ge)字检讨书

今天早上心情很好,然后我想AC几道题来展示自己很牛逼。[手动滑稽]
然后我就想找一找简单的题来练练。
突然想起codevs黄金天梯赛里有三道高精度的练习题,然后翻了翻,很快解决了高精度加减法。
然后我就开始无情嘲笑高精度乘法 因为我觉得我写得很爽很6啊。
对高精度加法有疑问的看这里,这篇博文里使用运算符重载写高精度加法,你写一个+号就会自动用高精度处理。不会运算符重载?这里也会教你!
然后一遍过样例~~~~~~
心情愉快的无法想象。
然后提交。
在这里插入图片描述
这真 * * 大块人心。。。。。。
然后愉(jue)快(wang)地坐在电脑面前长达两小时。。。。。。
这数据是给人调试的么

大佬:对啊!!!

高精度练习之乘法

题目描述 Description
给出两个正整数A和B,计算A*B的值。保证A和B的位数不超过500位。

输入描述 Input Description
读入两个用空格隔开的正整数

输出描述 Output Description
输出A*B的值

数据范围及提示 Data Size & Hint
两个正整数的位数不超过500位

样例输入 Sample Input样例输出 Sample Output
3 1236

时间限制: 1 s
空间限制: 128000 KB
这样例水啊。
难怪我可以一遍过样例

僵化的思维

图论题写了就会这样,老想弄一个什么模板。
然而高精度的四则运算本身就是一个大模板,那么我到底是在什么地方死脑筋呢?

首先,看见高精度运算,这就一定会想到本质就是一道模拟题。模拟那还不简单?白银赛里面的模拟题都做过了你高精度又能算什么?
然而高精度加减法确实简单,使用朴素模拟法就可以搞定。可是乘法未必。
如下是我WA的代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxm=2019;
char ta[maxm],tb[maxm];
int a[maxm],b[maxm],c[maxm],e[maxm][maxm];
int lena,lenb,lenc,flag;

int main(){
	std::ios::sync_with_stdio(false);
	cin>>ta>>tb;
	lena=strlen(ta);lenb=strlen(tb);
	lenc=max(lena,lenb);
	for(int i=0;i<=lenc-1;i++){
		a[i+1]=ta[i]-48;
		b[i+1]=tb[i]-48;
		if(a[i+1]==-48) a[i+1]=0;
		if(b[i+1]==-48) b[i+1]=0;
	}
	
	int high=0,wide=0;
	for(int i=lena,p=1;i>=1;i--,p++){
		for(int j=lenb,q=p;j>=1;j--,q++){
			e[p][q]=a[i]*b[j];
			if(e[p][q]>=10){
				int t=e[p][q]+flag;
				e[p][q]=t%10;flag=t/10;
				if(j==1){
					e[p][++q]=flag;
					flag=0;
					wide=max(wide,q);
				}
				continue;
			}
			wide=max(wide,q);
		}
		high=p;
	}flag=0;
	
	int f=1;
	for(int i=1;i<=wide;i++){
		for(int j=1;j<=high;j++)
			c[i]+=e[j][i];
		if(c[i]+flag>=10){
			int t=c[i]+flag;
			flag=t/10;c[i]=t%10;
			if(i==wide){c[0]=flag;f=0;}	
			continue;
		}
		c[i]+=flag;
		flag=0;
	}
	
	for(int i=1;i<=wide>>1;i++) 
		swap(c[i],c[wide-i+1]);
	for(f;f<=wide;f++)
		cout<<c[f];
	return 0;
}

我使用了二维数组来处理错位相加。形如这样的模拟手算:

      1 4 5 6
    6 8 3
8 5 5 1

然而,为了方便,我把他处理成这样:

6 5 4 1
  3 8 6
    1 5 5 8

这是我犯得最大的错误。这就导致我到最后不得不使用这个循环纵向统计竖下来的所有数字。最后逆序输出。但是这样显然是错误的,只是能过我自己手造的数据而已。
而且最后还要模拟一遍高精度运算。。。。。。

int f=1;
for(int i=1;i<=wide;i++){
	for(int j=1;j<=high;j++)
		c[i]+=e[j][i];
	if(c[i]+flag>=10){
		int t=c[i]+flag;
		flag=t/10;c[i]=t%10;
		if(i==wide){c[0]=flag;f=0;}	
		continue;
	}
	c[i]+=flag;
	flag=0;
}

这样代码量就很大,而且还弄不懂是哪里错了。

题解

事实上,根本没必要用二维数组列出这样的表。
我们每求出一组数据就写入答案,最后数据求完答案就出来。
还是以刚刚这个为例子:

      1 4 5 6
    6 8 3
8 5 5 1

比如我们现在求出1 4 5 6
然后接下来求出了6 8 3
那么我们可以直接酱紫放到一个一维数组里头

放置前:0 0 0 1 4 5 6
放置后:0 0 6 9 7 5 6 就是(0 0 0+6 1+8 4+3 5 6)

这样就满足按位相加了。
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define maxm 2019
int main(){
//	freopen("gin.txt","r",stdin);
    char a1[maxm],b1[maxm];
    int a[maxm],b[maxm],c[maxm],lena,lenb,lenc,i,j,x;
    cin>>a1>>b1;
    lena=strlen(a1);lenb=strlen(b1);
    for (i=0;i<=lena-1;i++) a[lena-i]=a1[i]-48;
    for (i=0;i<=lenb-1;i++) b[lenb-i]=b1[i]-48;
    for (i=1;i<=lena;i++){
         x=0;                                               
         for (j=1;j<=lenb;j++){
            c[i+j-1]=a[i]*b[j]+x+c[i+j-1];      
            x=c[i+j-1]/10;
            c[i+j-1]%=10;
         }
         c[i+lenb]=x;                                  
    }
    lenc=lena+lenb;
    while (c[lenc]==0&&lenc>1)       
        lenc--;
    for (i=lenc;i>=1;i--)
        cout<<c[i];
    cout<<endl;
    return 0;
}

不过真实写出代码,就不会像刚刚模拟的一样这么简单。为了生成0 0 0 1 4 5 6 这样的数据,不可能在前面打这么多0吧。。。(要这样也可以就是很复杂)
所以这段代码在这里对输入的数据进行逆序处理同时把字符化为数字:

for(i=0;i<=lena-1;i++) a[lena-i]=a1[i]-48;
for(i=0;i<=lenb-1;i++) b[lenb-i]=b1[i]-48;

这样我们可以直接从存答案的数组c中的下标1开始计算(从前往后而不是朴素模拟的从后往前)
代码简短,程序简单,请一定拿着纸和笔模拟!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值