整除与同余
整除和同余理论
同余方程
定义:形如 的方程。
裴蜀定理
内容:若 为正整数,则 有整数解当且仅当 为 的因数。
exgcd(扩展欧几里得算法)
扩展欧几里得算法(exgcd)——可求解 ,解同余方程、乘法逆元。
内容:对于形如 的方程,当 时, 是方程的一组特解。
模板
inline int exgcd(int a,int b,int &x,int &y) { int d=a; if(b==0) x=1,y=0; else d=exgcd(b,a%b,y,x),y-=(a/b)*x; return d; }
乘法逆元
定义:若 ,就称 与 在模 意义下互为乘法逆元。
例:
若要求 ,则转化为 ,其中 表示模 意义下 的逆元。
标准分解式
定义:将质因数分解的结果,按照质因数大小,由小到大排列,并将相同质因数的连乘积,以指数形式表示。
例:
的标准分解式为 。
欧拉函数
定义: 指在小于 的正整数中与 互质的数的个数。
求法:
1.先化为标准分解式:
2.再根据公式计算:
但当 为合数时,且不知道 的因数分解式时,通常很难求出 的欧拉函数值 。
欧拉函数线性筛法,时间复杂度
模板
const int MAXN=4e4+5; int phi[MAXN],prime[MAXN],m,ans; bool vis[MAXN]; inline void getphi() { phi[1]=1; for(int i=2;i<=MAXN;i++) { if(!vis[i]) prime[++m]=i,phi[i]=i-1; for(int j=1;j<=m;j++) { if(i*prime[j]>MAXN) break; vis[i*prime[j]]=true; if(!(i%prime[j])) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } }
欧拉定理
内容:对于两个正整数 ,若 互质,则
一般常用到它的推论:对于两个正整数 ,若 互质,则
利用这个推论,在满足 互质的前提下,即使 较大,我们也可以轻松地计算 的值。
扩展欧拉定理
通常用来解决欧拉定理的推论中 不互质时的情况。
内容:
费马小定理
定义:设 是一个素数,则对于任意整数 ,有
同样可以用来求逆元。
威尔逊定理
定义:对于一个素数 ,有
BSGS(大步小步算法)
通常用来求解离散对数问题,即求解形如 的方程的解。
内容:
取 ,令 ,则
预处理出所有 并哈希存储,枚举 后判断是否有满足条件的即可。
模板
inline int BSGS(int a,int b,int MOD) { map<int,int>ma; int cur=1,t=sqrt(MOD)+1; for(int i=1;i<=t;i++) { cur=cur*a%MOD; ma[b*cur%MOD]=i; } int now=cur; for(int i=1;i<=t;i++) { if(ma[now]) return i*t-ma[now]; now=now*cur%MOD; } return -1; }
CRT(中国剩余定理)
通常用来求解形如
的同余方程的解,其中 均为质数。
内容:
设
那么我们可以发现
于是答案便为
有时需要用到龟乘。
模板
inline int exgcd(int a,int b,int &x,int &y) { int d=a; if(b==0) x=1,y=0; else d=exgcd(b,a%b,y,x),y-=(a/b)*x; return d; } int a[MAXN],b[MAXN],n; inline int CRT(int mod) { int ans=0; for(int i=1;i<=n;i++) { int M=mod/a[i]; int x,y; int d=exgcd(M,a[i],x,y); ans=((ans+x*M*b[i])%mod+mod)%mod; } return ans; }
exCRT(扩展中国剩余定理)
内容:
对于上面的方程,假设合并两个方程:
那么合并出来的模数一定是 。
于是有:.
用 求出 即可。
其中无解的情况就是 无解的情况。
模板
int n,a[MAXN],b[MAXN]; inline int exgcd(int a,int b,int &x,int &y) { int d=a; if(b==0) x=1,y=0; else d=exgcd(b,a%b,y,x),y-=(a/b)*x; return d; } inline int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } inline int lcm(int a,int b) { return a/gcd(a,b)*b; } inline int Mod(int x,int p) { return (x%p+p)%p; } int x0,y0; inline int exCRT(int A,int B) { for(int i=2;i<=n;i++) { int g=Mod(b[i]-B,a[i]),d=exgcd(A,a[i],x0,y0); if(g%d) printf("No Solution\n"); x0*=g/d,x0%=a[i]/d; B+=A*x0,A=lcm(A,a[i]),B=Mod(B,A); } return B; }
本文作者:Code_AC
本文链接:https://www.cnblogs.com/code-ac/p/16795596.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步