2015年辽宁省赛热身赛有一道高精度乘法

传送门:NEUOJ 1574 A*B

1574: A * B

时间限制: 10 Sec  内存限制: 128 MB

题目描述

Calculate $a \times b$.

输入

Your program will be tested on one or more test cases. In each test case, two integer $a$, $b$ ($0\le a,b\le 10^{100000}$).

输出

For each test case, print the following line:

answer

where answer is $a\times b$.

样例输入

1000000000000000 2000000000000000

样例输出

2000000000000000000000000000000

提示

来源

2015省赛热身赛

朴素高精度乘法的典型写法是

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int MAX_N=1e5+10;
 5 char sa[MAX_N], sb[MAX_N];
 6 int a[MAX_N], b[MAX_N], res[MAX_N<<1];
 7 int main(){
 8     //freopen("in", "r", stdin);
 9     while(~scanf("%s%s", sa, sb)){
10         int i, j;
11         memset(res, 0, sizeof(res));
12         for(i=0; sa[i]; i++){
13              for(j=0; sb[j]; j++){
14                  res[i+j]+=(sa[i]-'0')*(sb[j]-'0');
15              }
16         }
17         int tot=i+j-2;    //error-prone
18         for(i=tot; i; i--){
19             res[i-1]+=res[i]/10;
20             res[i]%=10;
21         }
22         printf("%d", res[0]);    //error-prone
23         if(res[0]) for(i=1; i<=tot; i++) printf("%d", res[i]);
24         puts("");
25     }
26     return 0;
27 }

但这样写会TLE。下面要介绍一种常数优化:

将大整数从低位到高位每 $6$ 位分成一组(最后一组若不够 $6$ 位自动在高位补 $0$),这样便自然得到了大整数的「一百万进制」表示将每组内的十进制计数看成是一百万进制的一个“数字”,由于小于一百万的数的乘法无需采用高精度计算,可认为是 $O(1)$ 的,实际上对于不致溢出的小整数,机器实现的乘法比模拟竖式计算要快好多。这样便在原来十进制表示下的朴素高精度乘法的基础上,实现了常数优化。这样的常数优化常常是有效的。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define set0(a) memset(a, 0, sizeof(a))
 4 using namespace std;
 5 const int MAX_N=1e5+10;
 6 typedef long long ll;
 7 char sa[MAX_N], sb[MAX_N];
 8 ll a[MAX_N], b[MAX_N], res[MAX_N<<1];
 9 int base=6;
10 ll mod=1e6;
11 int trans(char *s, ll *a){  //value-passed
12     //memset(a, 0, sizeof(a));    //error-prone
13     int ls=strlen(s), len=(ls+base-1)/base;
14     int now=0, rem=ls%base;
15     int l, r;
16     if(rem){
17         l=0; r=rem;
18         for(int i=r-1, p=1; i>=l; i--, p*=10){
19             a[0]+=(s[i]-'0')*p;
20         }
21         now++;
22     }
23     for(int i=0; now<len; now++, i++){
24         l=rem+base*i, r=l+base; //error-prone
25         for(int j=r-1, p=1; j>=l; j--, p*=10){
26             a[now]+=(s[j]-'0')*p;
27         }
28     }
29     return len;
30 }
31
32 int main(){
33     //freopen("in", "r", stdin);
34     while(~scanf("%s%s", sa, sb)){
35         set0(a); set0(b); set0(res);
36         int la=trans(sa, a), lb=trans(sb, b);
37         for(int i=0; i<la; i++){
38             for(int j=0; j<lb; j++){
39                 res[i+j]+=a[i]*b[j];
40             }
41         }
42         int tot=la+lb-2;
43         for(int i=tot; i; i--){
44             res[i-1]+=res[i]/mod;
45             res[i]%=mod;
46         }
47         int i;
48         for(i=0; i<=tot&&!res[i]; i++);
49         if(i>tot) putchar('0');
50         else{
51             printf("%lld", res[i++]);   //error-prone
52             for(; i<=tot; i++) printf("%06lld", res[i]);
53         }
54         puts("");
55     }
56     return 0;
57 }

Time: 4158MS

选择每 $6$ 个分一组是要保证运算过程不会溢出 long long,就本题的数据范围而言,取 $7$ 位分为一组也可,这样常数会更优,只需将上面的代码稍加修改(注意加粗的三行)

 1 #include<cstdio>
 2 #include<cstring>
 3 #define set0(a) memset(a, 0, sizeof(a))
 4 using namespace std;
 5 const int MAX_N=1e5+10;
 6 typedef long long ll;
 7 char sa[MAX_N], sb[MAX_N];
 8 ll a[MAX_N], b[MAX_N], res[MAX_N<<1];
 9 int base=7;
10 ll mod=1e7;
11 int trans(char *s, ll *a){  //value-passed
12     //memset(a, 0, sizeof(a));    //error-prone
13     int ls=strlen(s), len=(ls+base-1)/base;
14     int now=0, rem=ls%base;
15     int l, r;
16     if(rem){
17         l=0; r=rem;
18         for(int i=r-1, p=1; i>=l; i--, p*=10){
19             a[0]+=(s[i]-'0')*p;
20         }
21         now++;
22     }
23     for(int i=0; now<len; now++, i++){
24         l=rem+base*i, r=l+base; //error-prone
25         for(int j=r-1, p=1; j>=l; j--, p*=10){
26             a[now]+=(s[j]-'0')*p;
27         }
28     }
29     return len;
30 }
31
32 int main(){
33     //freopen("in", "r", stdin);
34     while(~scanf("%s%s", sa, sb)){
35         set0(a); set0(b); set0(res);
36         int la=trans(sa, a), lb=trans(sb, b);
37         for(int i=0; i<la; i++){
38             for(int j=0; j<lb; j++){
39                 res[i+j]+=a[i]*b[j];
40             }
41         }
42         int tot=la+lb-2;
43         for(int i=tot; i; i--){
44             res[i-1]+=res[i]/mod;
45             res[i]%=mod;
46         }
47         int i;
48         for(i=0; i<=tot&&!res[i]; i++);
49         if(i>tot) putchar('0');
50         else{
51             printf("%lld", res[i++]);   //error-prone
52             for(; i<=tot; i++) printf("%07lld", res[i]);
53         }
54         puts("");
55     }
56     return 0;
57 }

 Time: 2937MS(这结果在所有AC的提交中算是很优的了)

当然高精度乘法有复杂度更优的解法,比如快速傅立叶变换(FFT),但通过本题,我们看到这种代码量较小的分组常数优化对于 $N$ 不太大,时限较宽的问题还是很有效的。

转载于:https://www.cnblogs.com/Patt/p/4625353.html

朴素高精度乘法的常数优化相关推荐

  1. python高精度乘法_洛谷P1919--A*B Problem升级版(NTT优化高精度乘法)

    题目背景 本题数据已加强,请使用 FFT/NTT,不要再交 Python 代码浪费评测资源. 题目描述 给你两个正整数 a,b,求$ a \times b$. 输入格式 第一行一个正整数,表示 a: ...

  2. C语言实现高精度乘法

    大一小白尝试C语言高精度乘法 一.高精度乘法是什么 高精度乘法就是对于普通数据类型无法表示的大整数进行乘法运算. 二.为什么需要高精度乘法 在C语言中,常用的数据类型有int, long long, ...

  3. OI常用的常数优化小技巧

    注意:本文所介绍的优化并不是算法上的优化,那个就非常复杂了,不同题目有不同的优化.笔者要说的只是一些实用的常数优化小技巧,很简单,虽然效果可能不那么明显,但在对时间复杂度要求十分苛刻的时候,这些小的优 ...

  4. 机器学习:SVM代码实现,朴素实现基础上的优化

    SVM代码实现,朴素实现基础上的优化: 因为二次凸优化已经把解析结果明白表现出来了,所以优化只能体现在两个变量的选择上,或者说是两个样本的选择上: 1.第一个变量的选择:这次实现也并不是选择最不满足K ...

  5. FFT实现高精度乘法

    你应该知道$FFT$是用来处理多项式乘法的吧. 那么高精度乘法和多项式乘法有什么关系呢? 观察这样一个$20$位高精度整数$11111111111111111111$ 我们可以把它处理成这样的形式:$ ...

  6. /* program p5_04_AC 《聪明人的游戏提高篇》 1307:【例1.3】高精度乘法

    /* program p5_04_AC <聪明人的游戏提高篇>  1307:[例1.3]高精度乘法 http://ybt.ssoier.cn:8088/problem_show.php?p ...

  7. 信息学奥赛一本通 1307:【例1.3】高精度乘法 | 1174:大整数乘法 | OpenJudge NOI 1.13 09:大整数乘法

    [题目链接] ybt 1307:[例1.3]高精度乘法 ybt 1174:大整数乘法 OpenJudge NOI 1.13 09:大整数乘法 [题目考点] 1. 高精度 考察:高精乘高精 高精度计算讲 ...

  8. 信息学奥赛一本通(1307:【例1.3】高精度乘法)

    1307:[例1.3]高精度乘法 时间限制: 1000 ms         内存限制: 65536 KB 提交数: 30399     通过数: 10666 [题目描述] 输入两个高精度正整数M和N ...

  9. 算法提高 高精度乘法(java)

    算法提高 高精度乘法 描述 在C/C++语言中,整型所能表示的范围一般为-231到231(大约21亿),即使long long型,一般也只能表示到-263到263.要想计算更加规模的数,就要用软件来扩 ...

最新文章

  1. 查找python项目依赖并生成requirements.txt的两种方法
  2. PowerDesigner 企业架构模型 ( EAM ) 说明
  3. Windows 7 64位系统上搭建Hadoop伪分布式环境(很详细)
  4. mysql: order by, group by ,having, select, where 执行 顺序
  5. 全志R40 UBOOT 2014.07【原创】
  6. web前端基础(01html基本标签)
  7. u-boot编译连接分析
  8. 解决百度云下载过慢、Linux下载百度云数据问题
  9. 21天Jenkins打卡Day16-清理工作空间
  10. Spark SQL将rdd转换为数据集-反射来推断Inferring the Schema Using Reflection
  11. python抛出异常 后如何接住,Python 异常的捕获、异常的传递与主动抛出异常操作示例...
  12. 2021“华为杯”第十八届中国研究生数学建模竞赛有感
  13. jmeter常用操作说明
  14. 每日excel学习之排序与筛选
  15. pb+api实际应用
  16. 运用R语言绘制小提琴图
  17. 极简试用期转正述职报告PPT模板
  18. O2O、C2C、B2B、B2C是什么意思 有什么区别
  19. html自学网页制作,HTML入门学习教程:简单网页制作
  20. 学习java随堂练习-20220623

热门文章

  1. 打不开_网页打不开,怎解?
  2. list redis 怎样做排行_学 Redis 的 7000 字小结!!!
  3. inum在linux中含义,linux
  4. sql列转行函数oracle,SQL列转行
  5. html5考试总结300字,期中考心得300字5
  6. hive udf 分组取top1_Hive的经典面试题
  7. 史上最全SQL优化方案(二)
  8. 数据结构--搜索BFS
  9. 神经网络基础:(1)得分函数 or 得分函数
  10. PCL:自定义创建带颜色的点云保存后rgb是一个很大的数,由x y z rgb解包为x y z r g b