同余方程-5天从入门到入土
LeavingZzz · · 算法·理论
upd: 应评论区,我自己查了一些资料之后发现原来写的东西确实有些不对的地方,造成的误解请各位海涵,本人蒟蒻,如果对于某个描述还是有疑问的话欢迎继续指出,谢谢各位 ^_^
特别鸣谢
目录
- 概念讲解
- 基础算法-解单个线性同余方程
- 进阶-解模数互质的线性同余方程组
- 再进阶-解一般的线性同余方程组
- 入坑-解未知数在指数位置且模数为质数的同余方程
- 入土-解未知数在指数位置的一般模数同余方程
(为什么没了呢?因为我不会了TAT)
\color{brown}\texttt{同步题单戳这里}
概念
1.带余除法
实际上就是小学学的那种“
本文中的除法都是整数除法
2.同余方程
同余方程就是长成这样的柿子:
这个式子什么意思? 就是字面意思,同余即指余数相同(
算法
Day 1.\mathsf{Exgcd} (扩展欧几里得算法)(求解二元一次不定方程/单个线性同余方程)
不定方程
我们先看一下简单一点的一个方程
证明
设
则
则
为了使
则
所以
此时
所以
即
证毕
证明
已证:
所以我们可以得到推论:
所以当
方程变成
所以一定有一组解
证毕
利用这个方法我们可以递归到边界(
然后在递归返回的时候更新
由于方程
而 除号当然是整除啦
方程左边
所以转化后新的
但是代码实现可以更简单一些,利用传引用在访问下一层递归的时候就交换
Code
int g,x,y;
void Exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;y=0;g=a;
return ;
}
Exgcd(b,a%b,y,x);//交换
y-=(a/b)*x;
return ;
}
那么解决了方程
我们解出
如果有解,那么解为
通解为
利用 Exgcd 可以解决较为基本的不定方程和同余方程问题
时间复杂度
\texttt{NOIP2012同余方程} \texttt{P1516青蛙的约会} \texttt{[模板]二元一次不定方程}
Day 2.\mathsf{CRT} (中国剩余定理/孙子定理)(求解模数两两互质的线性同余方程组)
(线性的意思就是一次的方程) 同余方程组长这样:
其中
证明中国剩余定理
因为
所以
又因为
所以当
即方程组的解为
证毕
当题目保证给出的模数两两互质的时候,
步骤:
- 求出
M=\prod\limits_{i=1}^{n}m_i - 利用 Exgcd 求出
M_iK_i\equiv 1\pmod {m_i} 的解K_i - 逐步累加
r_iM_iK_i (即利用x=\sum\limits_{i=1}^{n}r_iM_iK_i )得到解(模M 意义下)
Code:
typedef long long LL;
LL CRT()
{
LL pro=1;
for(LL i=1;i<=N;i++)
pro*=m[i];
LL x,y,Mi;LL ans=0;
for(LL i=1;i<=N;i++)
{
Mi=pro/m[i];
Exgcd(Mi,m[i],x,y);//x即为求解的K_i
ans=(ans+Mi*r[i]*x)%pro;
}
return (ans+pro)%pro;
}
时间复杂度
\texttt{模板P1495} \texttt{[TJOI2009]猜数字}
Day 3.\mathsf{ExCRT} (扩展中国剩余定理/孙子定理)(求解一般的线性同余方程组)
不是所有的方程组模数都两两互质(正如不是所有牛奶...算了)
那么现在所有的
这样的话方程
好的那么现在你面对的是?
Q:现在你会什么? A:解一个方程
假设我们解出来了第一个方程,将其解设为
我们现在的目的就是要求一个同时满足第一第二两个方程的
即求解不定方程
解出来
那么前两个同余方程等价为:
为什么等价?
因为向方程中代入
你会发现这两个方程和上面的等价方程同时成立,所以这里可以等价
那么你就会发现一件事情,你成功地把两个方程整成了一个方程
那么下一步,继续从方程组里面拿一个方程出来,这时候你手上又有了两个方程
由于第一个方程的通解是
所以我们就是要求一个满足条件的
所以就是求解
变形得
即求解不定方程
如果方程无解,则同余方程组无解
方程有解,那么解
循环求解即可。
形式化描述过程就是:
设
那么对于第
不定方程无解则同余方程组无解
得到
前
此时可求解第
inline LL ExCRT()
{
LL ans=0,lcm=1;
LL k1,k2,c;
for(int i=1;i<=N;i++)
{
Exgcd(lcm,m[i],k1,k2);
c=((r[i]-ans)%m[i]+m[i])%m[i]; // c=r2-r1(顺便调整为正的)
if(c%g) return -1; //无解
k1=((k1*c/g)%(m[i]/g)+(m[i]/g))%(m[i]/g);
ans=ans+k1*lcm;
lcm=lcm*m[i]/g; //lcm=lcm(lcm,m_i)
ans=(ans%lcm+lcm)%lcm;
}
return (ans%lcm+lcm)%lcm;
}
时间复杂度
\texttt{模板P4777} \texttt{[NOI2018]屠龙勇士} \color{green}\texttt{[讲解]}
Day 4.\mathsf{BSGS} (\mathsf{Baby Step Giant Step} )(解未知数在指数位置且模数为质数的同余方程)
有时候事情并不会都是那么简单,经过之前几个小节内容的学习你应该已经可以熟练地解决线性同余方程的相关问题 但是啊
其中
首先我们想一下对于这个问题暴力怎么搞
当然直接枚举指数啊qwq
但是这样枚举的尽头是什么呢?
首先我们知道
所以我们发现实际上枚举指数的时候枚举
int a,m,r;
scanf("%d%d%d",&a,&m,&r);
int base=1;
for(int i=0;i<m-1;i++)
{
if(base==r) {printf("%d",i);return 0;}
base=(base*a)%m;
}
printf("no solution");
return 0;
但是假如现在
那么我们要对暴力算法进行改进,核心肯定是缩小枚举的范围
这就是
设
对于同余方程
左右两边同时除以
预处理分母,然后当模
分母怎么预处理呢?
因为我们的解形式是
预处理出
暴力枚举
若存在那么最小解就是
那么现在是不是能理解
我们在预处理哈希表的时候就是在走
枚举
LL BSGS()
{
Hash.clear();
//很多选手会使用map但是手写Hash的效率比map高了好几倍
LL D=B%C,sqrtm=ceil(sqrt(C));
for(int i=0;i<sqrtm;i++)
{
//预处理幂值,建立幂值到幂指数的映射
Hash.insert(D,i);
D=D*A%C;
}
LL t=ti=fast_pow(A,sqrtm),ans;
//快速幂求出A^sqrtm
for(int i=1;i<=sqrtm;i++)
{
if((ans=Hash.find(ti))!=-1)
//如果找到了
return i*sqrtm-ans;
ti=ti*t%C;
}
return -1;
}
时间复杂度
\texttt{模板P3846} \texttt{P4861按钮} \color{green}\texttt{[讲解]} \texttt{[CQOI2019]破解D-H协议} \color{green}\texttt{[讲解]} \texttt{P4884多少个1?} \texttt{[SDOI2013]随机数生成器} \texttt{[SDOI2011]计算器}
Day5.\mathsf{ExBSGS} (\mathsf{ExtendedBabyStepGiantStep} )(解未知数在指数位置的一般模数同余方程)
就像我们在
不互质的时候分式
我们只会互质的解法,怎么办?
没有条件创造条件!
对于同余方程
那么我们让他互质!
设
设
证明
设
化为不定方程
在学习
证毕
为了使模数互质我们执行消去因子达到
依据
对于方程
设
其中的
设
现在
但是这样得到的
inline LL BSGS()
{
LL sqrtm=ceil(sqrt(C));
H.clear();//手写Hash很香的qwq
LL t=B%C;
for(int i=0;i<sqrtm;i++)
{
H.insert(t,i);
t=t*A%C;
}
t=fast_pow(A,sqrtm,C);
LL ti=D*t%C,ans;//初始化成D*A^(i*sqrtm)
for(int i=1;i<=sqrtm;i++)
{
if((ans=H.find(ti))!=-1&&i*sqrtm-ans!=0)
return i*sqrtm-ans;
ti=ti*t%C;
}
return -1;
}
inline LL ExBSGS()
{
LL cnt=0;D=1;
if(B==1) return 0;
while((g=gcd(A,C))!=1)//消去因子
{
if(B%g) return -1;
B/=g;C/=g;
D=(D*A/g)%C;
cnt++;
if(D==B) return cnt;
//每消去一次g,D就会乘以A/g 在模C意义下出现D==B时消去了cnt次
//所以解为cnt
}
LL ans=BSGS();
if(ans==-1) return -1;
else return ans+cnt;
}
时间复杂度
\texttt{模板P4195} \texttt{模板SP3105}
如果还有任何对算法不理解的问题珂以私信窝,力所能及的范围内窝一定尽力解答 ^_^