数论-扩展欧几里得算法
证明链接:http://blog.csdn.net/acmore_xiong/article/details/47694909
模板:
void exgcd(ll a,ll b,ll&d,ll&x,ll&y){ if(!b){ d=a,x=1,y=0; return ; } exgcd(b,a%b,d,y,x); y-=x*(a/b); }
一、求解不定方程
1.青蛙的约会
题意:
本题其实是在求不定方程的解。根据题设条件,我们其实是需要找到一个整数p,使方程
(x+p·m)%L=(y+p·n)%L
有解。对L取模可以看成
x+p1·m=y+p1·n+p2·L
合并同类项,得到一个不定方程:
(n-m)·p1+L·p2=x-y
设a=n-m,b=L,c=x-y,如果c%gcd(a,b)==0,方程有解,我们的目的就是求出p1
样例解释:
x=1,y=2,m=3,n=4,L=5
a=(n-m)=1, b=L=5, c=x-y=-1
a·p1+b·p2=c → 1·p1+5·p2=-1 ,p1=4,p2=-1
转化为求扩展欧几里得的方程,1·p1’+5·p2’=1(gcd(1,5)=1,并且此时的p1'和p2'是中间解),两边同时乘以-1:(也就是c/r)
1·(-p1’)+5·(-p2’)=-1
1·p1+5·p2=-1
p1=-p1',可以求得p1=-1,p2=0.此时求得的解是方程的特解,再加上齐次通解就是方程的通解:
x=p1+k·b
y=p2-k·a
把k=1带入,解得ans=-1+5=4
求特解的代码:(此时p1=1,c=-1,b=5,ans=-1)
ll ans=c*p1-c*p1/b*b;
AC代码:
#include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 101 #define MAX 1<<30 #define V vector<int> #define ll long long using namespace std; ll gcd(ll a,ll b){ int c; while(b){ c=a%b; a=b; b=c; } return a; } void exgcd(ll a,ll b,ll& d,ll& x,ll &y){ if(!b){ d=a,x=1,y=0; return; } exgcd(b,a%b,d,y,x); y-=(a/b)*x; } int main(){ // freopen("青蛙约会.txt","r",stdin); ll x,y,n,m,L,a,b,c,r,p1,p2,d; while(~I("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)){ a=n-m,b=L,c=x-y; r=gcd(a,b); if(c%r){ puts("Impossible"); continue; } a/=r,b/=r,c/=r; exgcd(a,b,d,p1,p2); ll ans=c*p1-c*p1/b*b; // ll ans=(c/r)*p1; while(ans<0) ans+=b; printf("%lld",ans); } }