今天是李昊老师的讲授~~
总结了一下今天的内容:
1.高精度算法
(1) 高精度加法
思路:模拟竖式运算
注意:进位
优化:压位
程序代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
char a1[1000],b1[1000];
int a[1000],b[1000],c[1000];
int main(){
scanf("%s",a1);
scanf("%s",b1);
int lena=strlen(a1);
for(int i=lena-1;i>=0;i--)a[lena-i]=a1[i]-‘0‘;
int lenb=strlen(b1);
for(int i=lenb-1;i>=0;i--)b[lenb-i]=b1[i]-‘0‘;
int lenc=max(lena,lenb);
for(int i=1;i<=lenc;i++)c[i]=a[i]+b[i]; //先将每一对应位加起来
for(int i=1;i<=lenc;i++){
c[i+1]+=c[i]/10; //进位
c[i]%=10;
}
while(c[lenc+1]>0) lenc+=1; //如果位数增多,则lenc++
for(int i=lenc;i>0;i--)
cout<<c[i];
return 0;
}
考虑负数的情况:
若只有一个负数,那么就成为正加数-另一个加数的形式;
若有两个负数,那么先算两个数的绝对值的和,再加上个负号‘-’;
(2) 高精度减法
思路:模拟竖式运算,考虑进位
注意:结果为0的情况
程序代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
char a1[1000],b1[1000];
int a[1000],b[1000],c[1000];
int main(){
scanf("%s",a1);
scanf("%s",b1);
int lena=strlen(a1);
for(int i=lena-1;i>=0;i--)a[lena-i]=a1[i]-‘0‘;
int lenb=strlen(b1);
for(int i=lenb-1;i>=0;i--)b[lenb-i]=b1[i]-‘0‘;
int lenc=max(lena,lenb);
for(int i=1;i<=lenc;i++)c[i]=a[i]-b[i]; //先将每一对应位都相减,方便借位处理
for(int i=1;i<=lenc;i++){
if(c[i]<0) //若不够0,就向高位借位+10,高位--
{
c[i]+=10;
c[i+1]--;
}
}
while(c[lenc]==0) lenc--; //除去前导0
for(int i=lenc;i>0;i--)
cout<<c[i];
return 0;
}
考虑负数的情况:
若只有一个负数:
<1>负数-正数 转化为两数绝对值相加,然后在前面加个负号‘-’;
<2>正数-负数 转化为两数绝对值相加;
若有两个负数:
转化为被减数的绝对值-减数的绝对值;
!!!小数减大数de处理方法:
用大数减小数,然后在前面加上负号‘-’;
(3) 高精度乘法
思路:模拟竖式运算,考虑进位
注意:结果为0的情况
程序代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
char a1[1000],b1[1000];
int a[1000],b[1000],c[1000];
int main(){
scanf("%s",a1);
scanf("%s",b1);
int lena=strlen(a1);
for(int i=lena-1;i>=0;i--)a[lena-i]=a1[i]-‘0‘;
int lenb=strlen(b1);
for(int i=lenb-1;i>=0;i--)b[lenb-i]=b1[i]-‘0‘;
int lenc;
for(int i=1;i<=lena;i++)
for(int j=1;j<=lenb;j++)
c[i+j-1]+=a[i]*b[j]; //对应位相乘
for(int i=1;i<lena+lenb;i++)
{
c[i+1]+=c[i]/10; //进位
c[i]%=10;
}
lenc=lena+lenb-1;
while(c[lenc+1]>0) lenc++; //如果位数增多,lenc++
for(int i=lenc;i>0;i--)
cout<<c[i];
return 0;
}
考虑负数的情况:
若有一个负数: 正常绝对值相乘,前面加负号‘-’;
若有两个负数: 正常绝对值相乘;
(4) 高精度除法 ——高精除单精
思路:模拟竖式运算
程序代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
char a1[1000];
int a[1000],b[1000],c[1000],b1;
int main(){
scanf("%s",a1);
cin>>b1;
int lena=strlen(a1);
for(int i=lena-1;i>=0;i--)a[lena-i]=a1[i]-‘0‘;
for(int i=lena;i>0;i--){
c[i]=a[i]/b1;
a[i-1]+=(a[i]%b1)*10; 第lena位除以b1后的余数*10+第lena-1位的数继续除
}
while(c[lena]==0 && lena>0)lena--;
for(int i=lena;i>0;i--)printf("%d",c[i]);
return 0;
}
2.模意义下运算
例:
在模7意义下的运算:
3*3=9≡2 (mod 7)
4+5=9≡2 (mod 7)
4-5=-1≡6 (mod 7)
注意:无除法运算
那碰到除法的怎么办呢???
假设a*b=t(mod p):
我们都知道费马小定理:
如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)
t*a^(p-2)≡b (mod p)
t/a≡b (mod p)
so 模意义下/a相当于*a^(p-2)
模意义下运算的性质:
1.满足基本的交换律,分配率,结合律;
2.对中间结果取模不影响最终答案;
3.快速幂
首先让我们思考一下怎么求a^b%p?
有两种求法:
分治
简单说一下,就是要求a^b,那么我们就求a^(b/2)再平方就好啦,求a^(b/2)同理
快速幂
4.费马小定理
如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)
应用:
计算组合数C(n,m)%(10^9+7)
C(n,m)=n!/((n-m)!*m!)
=n!*((n-m)!*m!)^(p-2)
=n!*(((n-m)!)^(p-2)*(m!)^(p-2))
所以我们只要预处理任意n!,(n!)^(p-2)就好了
原文:https://www.cnblogs.com/xcg123/p/10657065.html