裴蜀定理与扩展欧几里得
裴蜀定理与扩展欧几里得
裴蜀定理
定理
对于任意整数
且对于
证明
设
设
展开得
根据模运算的性质有:
类似的,
设
展开得
根据模运算的性质有:
再者,设
由于
故有
裴蜀定理可以扩展到
也即
证明过程模仿
应用
裴蜀定理
如上文所说,只需要打一个GCD即可。
#include<iostream>
#include<cstdio>
using namespace std;
#define int long long
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
signed main(){
int n;cin>>n;
int a,ans;cin>>a;ans=a;
for(int i=2;i<=n;i++){
cin>>a;ans=gcd(ans,a);
if(ans<0)ans=-ans;
}
cout<<ans<<"\n";
}
向量
首先,减去
所以可以得到方程组:
设
所以说,
均为偶数,此时有: ,提取一个公约数 ,变成: ,同理可以得到: 。
均为奇数,此时有: ,再提取一个公约数 ,变成 。
为偶数, 为奇数,此时有: ,类似的我们可以得到: 。
为奇数, 为偶数,此时有: ,类似的我们可以得到: 。
四种情况满足一种即可,前提是
#include<iostream>
#include<cstdio>
using namespace std;
#define int long long//警钟长鸣
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
signed main(){
int n,a,b,x,y;cin>>n;
while(n--){
cin>>a>>b>>x>>y;
int d=gcd(a,b);
d<<=1;
if(x%d==0&&y%d==0)cout<<"Y\n";
else if((x+a)%d==0&&(y+b)%d==0)cout<<"Y\n";
else if((x+b)%d==0&&(y+a)%d==0)cout<<"Y\n";
else if((x+a+b)%d==0&&(y+a+b)%d==0)cout<<"Y\n";
else cout<<"N\n";
}
return 0;
}
模
这个题是真的得手玩了。
引理:一个数
证明:
由于一个数
分类讨论:
,此时
此时
进制下数位和 ,而由于当 时, ,所以根据因式分解的知识,其必然存在一个因式为 。此时说明 也符合引理。
尝试对
中的方法进行扩展。设其有 位,则 。 接着,将其拆开
得证。
这样的话,我们就只需要判断方程:
也即
#include<bits/stdc++.h>
using namespace std;
#define int long long//注意
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
signed main(){
int a,b,c,k,T;cin>>T;
while(T--){cin>>a>>b>>c>>k;
puts(c%(gcd(gcd(a,b),1-k))?"No":"Yes");
}
}
扩展欧几里得算法(exgcd)
应用:求解
算法思想
根据普通
这就意味着
这启发我们运用这个过程去解决方程。
显然我们可以根据
此时显然有一组解:
然后考虑回推。
设
带回式子,可以得到
整理一下,可以得到
所以
显然,求解
int exgcd(int a,int b,int &x,int &y){//注意传地址
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
那么回归正题:求解
根据裴蜀定理,其有解的充分必要条件是
方法一
先解出
方法二
显然,对于不定方程
下面提供方法一的代码:
void solve(int a,int b,int t,int &x,int &y){ //ax+by=t
int d=exgcd(a,b,x,y);
if(t%d){
puts("无解");return ;
}
x*=t/d,y*=t/d;
}
无穷解的讨论
设
设
拆开得到
显然,满足这个关系式的最小整数对
故可以得到:
其中
那么借助它,我们可以得到一些方法:
对于不定方程
得防负数)即可。同时就可以求出对应的
同余方程
还有一个应用就是解同余方程
这个式子可以转化为求解不定方程
解出这个式子,所有的
应用
青蛙的约会
根据题意,设
取
#include<iostream>
#include<cstdio>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
signed main(){
int a,b,m,n,l,x,y;cin>>x>>y>>m>>n>>l;
if(n<m){
swap(n,m);swap(x,y);
}
int d=exgcd(n-m,l,a,b);
int p=x-y;
if(p%d){
cout<<"Impossible\n";
}
else {
a=(a*(p/d)%(l/d)+(l/d))%(l/d);cout<<a<<"\n";
}
}
最大公约数问题
描述:求不定方程
显然,由于
#include<iostream>
#include<cstdio>
using namespace std;
inline int abs(int x){
return (x<0?-x:x);
}
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
int main(){
int t,a,b,x,y;
cin>>t;
while(t--){
cin>>a>>b;
int d=exgcd(a,b,x,y);
int ans=1e9;
x=(x%b+b)%b,y=(d-a*x)/b;
ans=x-y;int xx=x,yy=y;
y=(y%a+a)%a,x=(d-b*y)/a;
if(abs(xx)+abs(yy)<abs(x)+abs(y))cout<<xx<<" "<<yy<<"\n";
else cout<<x<<" "<<y<<"\n";
}
}
荒岛野人
这个题注意观察到
注意枚举的下界就是野人居住洞穴的编号最大值。
注意不能二分/倍增,会爆掉的。(答案是不规则的)。
#include<iostream>
#include<cstdio>
using namespace std;
#define N 105
#define int long long
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
int c[N],p[N],l[N],n;
bool check(int mid){
int x,y;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int a=p[i]-p[j],b=mid,C=c[j]-c[i];
int d=exgcd(a,b,x,y);
if(C%d)continue;
x=x*(C/d);b/=d;
if(b<0)b=-b;
int ti=(x%b+b)%b;
if(ti>l[i]||ti>l[j])continue;
return false;
}
}
return true;
}
signed main(){
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
cin>>c[i]>>p[i]>>l[i];
ans=max(ans,c[i]);
}
while(!check(ans))++ans;
cout<<ans<<"\n";
}
conscious
观察数据范围
借助裴蜀定理,我们其实是可以确定
根据裴蜀定理,
所以我们可以发现,可能的
注意
这两个决策谁更优呢?设
,说明 更优 ,说明 一样优,此时对二者的 的最小正值取较小值。 ,说明 更优。
求出最优方案中对应的
注意若
#include<bits/stdc++.h>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
int solve(int a,int b,int k){//ax+by=k
int x,y;int d=exgcd(a,b,x,y);
b/=d,x*=k/d;
return (x%b+b)%b;
}
signed main(){
ios::sync_with_stdio(false);
int T;cin>>T;
while(T--){
int sb,ans,res,a,m,sub,x,y;cin>>a>>m>>sub;int d=exgcd(a,m,x,y);
int p=sub%d;
if(sub+d-p>=m||p+p<d)
ans=solve(a,m,sub-p);
else if(p+p>d)
ans=solve(a,m,sub+d-p);
else {
ans=min(solve(a,m,sub-p),solve(a,m,sub+d-p));
}
res=ans;ans=((res*a)%m+m)%m;
if(abs(ans-sub)>=sub){
cout<<"0 0\n";continue;
}
cout<<ans<<" "<<res<<"\n";
}
return 0;
}
AHOI2005洗牌
注意观察,手玩几组会发现一个规律:位置为
所以本题实际解决的是:
进行移项变式,可以得到
#include<iostream>
#include<cstdio>
using namespace std;
#define int __int128
#define ll long long
void read(int &x){
x=0;
char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=getchar();
}
int power(int a,int b,int p){
int ans=1;
while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans%p;
}
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
signed main(){
int n,m,l;
read(n),read(m),read(l);
int x,y;int d=exgcd(power(2,m,n+1),n+1,x,y);
x=(x%(n+1)+(n+1))%(n+1);
int inv=x;ll ans=inv%(n+1)*l%(n+1);
cout<<ans;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!