同余 与 数论其他
一.定理
费马小定理&欧拉定理
-
若
为质数且 ,则 . -
若
,则 . -
(扩展欧拉定理)若
,则有 .
二.算法
欧几里得算法
给定
我们发现,有:
利用这个东西递归计算即可。
扩展欧几里得(exgcd)
- 记
,求解下列方程:
设计函数 exgcd(ll a,ll b,ll &x,ll &y)
。
当
若已经知道了
于是我们就得到了一组解
代码:
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){ x=1,y=0;return a; }
ll d=exgcd(b,a%b,x,y);
ll z=x; x=y; y=z-y*(a/b);//妈妈生的!!a/b要带括号!!!
return d;
}
注:
方程
线性同余方程
求解同余方程
只需解出
当且仅当
//解同余方程 ax≡b(mod m)
ll TYFC(ll a,ll b,ll m){
ll x,y,mm;
ll G=exgcd(a,m,x,y);
if(b%G) return -1;
x*=b/G;mm=m/G;
return (x%mm+mm)%mm;
}
类欧几里得算法,万能欧几里得算法与 SB 树
单独写一篇博客了,在这里。
乘法逆元
同余方程
为奇质数
此时由费马小定理
如果要
不为质数
要求
可以试做方程
于是使用 exgcd 解方程就行。
中国剩余定理
参考:蓝书、oi-wiki。
用来求解以下方程组:
其中满足
我们记
于是我们有
证明也很简单,考虑方程
而对于
此时
扩展中国剩余定理
上述情况下如果不保证
蓝书是这么做的:
假设求出了
考虑第
解这个方程得到
如此来
阶与原根
参照这篇博客
一.定义
由欧拉定理,对于整数
也就是说,满足
如果有
二.性质
证明咕了。
当且仅当
证明咕了。
若
证明咕了。
若
时,
离线对数问题
求解方程
BSGS算法
此部分来源于算法竞赛进阶指南。
全称为 BabyStepGiantStep,适用于
为何必须限定
由欧拉定理,
设解为
即:
我们枚举
然后我们枚举
时间复杂度
点击查看代码
ll BSGS(ll a,ll b,ll p){
if(a%p==0){
if(b%p==1&&a!=0) return 0;
else if(b%p==0) return 1;
else return -1;
}
map <ll,int> mp; mp.clear();
b%=p;ll t=ceil(sqrt((double)p)),now=b;
for(int j=0;j<t;j++){
if(j) (now*=a)%=mod;
mp[now]=j;
}
now=1;a=qpow(a,t,p);
for(int i=0;i<=t;i++){
if(i) (now*=a)%=mod;
if(mp.find(now)!=mp.end()&&i*t-mp[now] >=0) return i*t-mp[now];
}return -1;
}
扩展BSGS算法
还是求解这个方程,但这里没有
我们做如下处理:
同余式不好处理,我们令:
记
若
若
其他情况下,我们让式子左右同时除以
即:
由于此时
发现这个问题和原问题一模一样,于是递归求解。
递归层数不超过
点击查看代码
ll TYFC(ll a,ll m){
ll x,y; exgcd(a,m,x,y);
return (x%m+m)%m;
}
ll exBSGS(ll a,ll b,ll p){
b%=p; if(b==1||p==1) return 0;
ll t=gcd(a,p);
if(b%t) return -INF;
if(t==1){
return BSGS(a,b,p);
}
ll inv=TYFC(a/t,p/t);
return exBSGS(a,b/t*inv,p/t)+1;
}
高次剩余
二次剩余
其他
斐波那契相关
不是,这玩意太邪门了。
我们记值域为
参考了这三篇博客:OneInDark,weixin_30414635
,hhoppitree
证明去翻这几篇博客吧,我反正是通篇不写证明,有空再写。
一.引理
对于任意正整数
二.算法流程
我们预处理这些东西:
以内的 表,复杂度为
代码:
for(int i=1;i<=t;i++){
gcd[i][0]=gcd[0][i]=i;
for(int j=1;j<=t;j++){
gcd[i][j]=gcd[j%i][i];
}
}
以内正整数的分解。
对于正整数
代码:
split[1][0]=split[1][1]=split[1][2]=1;
for(int i=2;i<=maxm-10;i++){
ll minn=INF,mini;
for(int j=0;j<3;j++){
split[i][j]=split[i/v[i]][j];
if(split[i][j] < minn) minn=split[i][j],mini=j;
}
split[i][mini] *= v[i];
}
接下来我们尝试实现
首先,对于
我们将
具体的,每局
然后我们让
代码:
ll Gcd(ll x,ll y){
if(x<=1010 && y<=1010) return ggcd[x][y];
ll res=1,tmp;
for(ll i=0;i<3;i++){
if(split[x][i]==1) continue;
if(split[x][i] <= 1010) tmp=ggcd[split[x][i]][y%split[x][i]];
else if(y%split[x][i]==0) tmp=split[x][i];
else tmp=1;
res *= tmp;y/=tmp;
}return res;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】