总结一波数论基础知识。。。。大佬勿入
拓展欧几里得:
这么水,直接上代码比较方便:
LL ex_gcd(LL a,LL b,LL &x,LL &y) //求解一个方程:ax+by=gcd(a,b)的一组特解。
{LL x1,y1,d;
if(b==0) //若b为0显然此时x=1,y=0
{x=1;y=0;return a;
}
d=ex_gcd(b,a%b,x1,y1);//将求解转化为求解方程:bx+(a%b)y=gcd(b,a%b)=gcd(a,b),顺便求一下gcd(a,b)
x=y1;y=x1-a/b*y1; //将得到的解转化一下。
return d;
}
乘法逆元
定义:记数 在模 意义下的乘法逆元为 ,即满足模方程:
逆元在求模数时十分有用。
注:有的数可能没有乘法逆元
求法1:
根据欧拉定理可得:对于任意整数 ,均存在:
故: 所以任意数 模 意义下的的乘法逆元为:
用快速幂求解即可。时间复杂度:
注:一般只用于 素数时,欧拉函数难得算,但是素数时 ,考试时一般用的是素数
~~不用贴代码了吧。。。水的很~~
求法2:
我们将模方程换一个方式写下:
移项得:
其中 为未知数,是不是很像方程:ax+by=1?
于是就可以用拓展欧几里得求解 如果不互质,要除掉gcd。
组合数
还是解释一下吧:
好了就这样吧。
求法1:数据小时打表啦
用递推式递推即可。
for(i=0;i<=2000;i++)c[i][0]=1;
for(i=1;i<=2000;i++)
for(LL j=1;j<=i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
求法2,求解的组合数中有炒鸡大的数,比模数还大:卢卡斯定理
卢卡斯定理很难说,直接上代码:
LL lucas(int x,int y){
if(x<mod&&y<mod)return C(x,y);
return (C(x%mod,y%mod)+C(x/mod,y/mod))%mod;
}
很简单对不对?剩下的可以用打表法预处理或者预处理阶乘求解即可。
求法3没有办法的办法:线性求C:
根据 线性求,时间复杂度 ,如果要取余还要求个逆元就是 。
void getc(int x,int y){
LL i,ans=1;
for(i=1;i<=x;i++)ans=((ans*(y-i+1))%mod*getni(i))%mod;
}
欧拉线性筛模板
还是看代码吧:在莫比乌斯反演中非常有用
int pi[100010],prime[100010];
bool mark[100010]
void getpi(){//欧拉线性筛,求解欧拉函数与质数
int cnt=0,i,j;
for(i=2;i<=n;i++){
if(!mark[i]){
prime[++cnt]=i;//若当前数没被筛到,则它是质数。
pi[i]=i-1;//质数的欧拉函数是该数减1
}
for(j=0;j<cnt&&i*prime[j]<=n){
mark[i*prime[j]]=true;
if(i%prime[j]==0){
pi[i*prime[j]]=phi[i]*prime[j];
break;
}
else pi[i*prime[j]]=phi[i]*(prime[j]-1);//分类讨论枚举
}
}
}
时间复杂度 时间用的很少的暴力筛。
顺便一提:欧拉函数与欧拉定理
欧拉函数: 为比n小且与n互质的数字个数。它的性质多得不得了。
欧拉定理:
这个没多大用处的。但是,它可以压缩快速幂的计算复杂度:
条件太苛刻了,于是又有拓展:
中国剩余定理:
对于一个数 ,对于所有 满足:
则它的最小正整数解为:
令 , , 为 在模 意义下的逆元。
则