演算法複習——擴充套件歐幾里得演算法(擴充套件歐幾里得,逆元,整除)
阿新 • • 發佈:2018-11-19
①歐幾里得演算法
就是求gcd的有趣的輾轉相除法,不再贅述啦0v0
程式碼:
int gcd(int a,int b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}
②擴充套件歐幾里得演算法
需要解決這樣的問題:兩個非0整數a,b,求一組整數解(x,y),使得ax+by=gcd(a,b).
(PS:證明之後補上0....0)
int exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1; y=0; return a; } int g=exgcd(b,a%b,x,y); int t=x; x=y; y=t-a/b*y; return g; }
③求逆元
可以解決這樣的問題:設a和m是整數,求a模m的逆元(逆元:設abm都是整數,m>1,有ab模m和1模m相等,它們擁有相同的餘數,那麼ab互為模m的逆元。也就是說,有兩個數的乘積,如果模m後等於1,則它們互為m的逆元)。
gcd(a,m)=1有解。
即求ax+my=1=gcd(a,m)。
程式碼:
ll inverse(ll a,ll m,ll c)
{
ll x,y;
ll g=exgcd(a,m,x,y);
if(c%g!=0)
return -1;
x*=c/g;
m/=g;
if(m<0)
m=-m;
ll ans=x%m;
if(ans<=0)
ans+=m;
return ans;
}
接下來給幾個例子0V0↓
例子1:zoj 3609,傳送門:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4712
題意:輸入一個n,給n組a和m,求每組a模m的最小逆元。
吐槽:m=1的情況……窒息了
程式碼:
//zoj 3609求最小逆元 #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<iostream> #include<map> #include<vector> #include<set> #include<queue> using namespace std; const int inf=0x3f3f3f3f; int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } int exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1; y=0; return a; } int g=exgcd(b,a%b,x,y); int t=x; x=y; y=t-a/b*y; return g; } int inverse(int a,int m) { int x,y; int g=exgcd(a,m,x,y); return (x%m+m)%m; } int main() { int a,m,n,x,y; cin>>n; while(n--) { cin>>a>>m; int ans=exgcd(a,m,x,y); if(m==1) { cout<<1<<endl; continue; } if(ans!=1) cout<<"Not Exist"<<endl; else { x%=m; if(x<0) x=(x%m+m)%m; cout<<x<<endl; } } return 0; }
例子2:hdu 1576,傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=1576
程式碼:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
int gcd(int a,int b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int g=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return g;
}
int inverse(int a,int m)
{
int x,y;
int g=exgcd(a,m,x,y);
return (x%m+m)%m;
}
int main()
{
int t,n,b;
cin>>t;
while(t--)
{
cin>>n>>b;
int m=9973;
int ans=inverse(b,m);
ans=ans*n%m;
cout<<ans<<endl;
}
return 0;
}
例子3:hdu2668,傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=2669
模板題0V0
程式碼:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll g=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return g;
}
ll inverse(ll a,ll m)
{
ll x,y;
ll g=exgcd(a,m,x,y);
return (x%m+m)%m;
}
int main()
{
ll a,m,x,y;
while(scanf("%lld %lld",&a,&m)!=EOF)
{
ll ans=exgcd(a,m,x,y);
if(ans!=1||m==1)
cout<<"sorry"<<endl;
else
{
x%=m;
if(x<0)
x=(x%m+m)%m;
cout<<x<<" "<<(1-a*x)/m<<endl;
}
}
return 0;
}
例子4:poj1061,傳送門:http://poj.org/problem?id=1061
程式碼:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll g=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return g;
}
ll inverse(ll a,ll m,ll c)
{
ll x,y;
ll g=exgcd(a,m,x,y);
if(c%g!=0)
return -1;
x*=c/g;
m/=g;
if(m<0)
m=-m;
ll ans=x%m;
if(ans<=0)
ans+=m;
return ans;
}
int main()
{
ll a,b,x,y,l;
while(scanf("%lld %lld %lld %lld %lld",&x,&y,&a,&b,&l)!=EOF)
{
ll ans=inverse(a-b,l,y-x);
if(ans==-1)
cout<<"Impossible"<<endl;
else
cout<<ans<<endl;
}
return 0;
}