清北学堂 DAY1

今天是李昊老师的讲授~~

总结了一下今天的内容:

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;
}

扫描二维码关注公众号,回复: 5779520 查看本文章

考虑负数的情况:

若只有一个负数,那么就成为正加数-另一个加数的形式;

若有两个负数,那么先算两个数的绝对值的和,再加上个负号‘-’;

(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)就好了

猜你喜欢

转载自www.cnblogs.com/xcg123/p/10657065.html