写这个也是为了自己更好的学习数学专题
1.欧几里德算法
作用:求两个数a和b的最大公约数。
gcd(a,b)=gcd(b,a%b)
我们可以看到,上式是将原来函数的第二个参数放到了第一个参数的位置,然后第二个参数的位置放上 原来的第一个参数%原来第二参数。
高中时学过一个辗转相除法。
我们可以举个例子。
求24和10的最大公约数:
24 ÷ 10 = 2 ……4
10 ÷ 4 = 2 ……2 下面一个式子的被除数是上面一个式子的除数,除数是上一个式子的余数。
4 ÷ 2 = 2 ……0
2 ÷ 0 (除数为0)→结果是 2
我们可以根据这个写一个程序:
#include <iostream>
#include <cstdio>
using namespace std;
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b))
{
printf("%d\n",gcd(a,b));
}
return 0;
}
我们来测试测试
我给出的例子是被除数(a)比除数(b)大的情况,这个很好理解。(我并没给出严格的证明,我们只要能理解、能运用就好)
如果a<b呢?
举个例子:10和24
10 ÷ 24 = 0 ……10
24 ÷ 10 = 2 ……4
.......
看到了如果 a<b那么gcd(a,b)的结果相当于 swap(a,b),gcd(a,b);
会把两个参数a,b交换位置,再调用一次。所以gcd(10,24)的结果gcd(24,10)相同,
(ps:这不是显然的吗?a、b的最大公约数是个定值)
我来考虑下这个函数的边界情况:
if(b==0 && a),那么直接返回a了,结果=a,
if(b && a==0),那么a<b,交换a,b的位置再调用一次,结果=b
if(a==0&&b==0) 结果返回0
注意:实际上我们不会去求0和另一个数的最大公约数。
2.证明两整数a,b互质的充要条件是:存在两个整数x,y满足ax+by=1
3.拓展欧几里德算法
递归终点方程组:
思想:
程序:
#include <iostream>
#include <cstdio>
using namespace std;
int exgcd(int a,int b,int &X,int &Y)//采用引用&,从递归终点不断修改X,Y值
{
if(!b)
{
X=1,Y=0;//Y可取任意值,这里姑且取0,这样得到的结果abs 更小
return a;
}
int ans=exgcd(b,a%b,X,Y);
int X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return ans;
}
int main()
{
int a,b,X,Y;
while(~scanf("%d%d",&a,&b))
{
exgcd(a,b,X,Y);
printf("结果:\n%d %d\n",X,Y);
}
return 0;
}
说明:
a*X+b*Y=gcd(a,b)的其它解:
a*X+b*Y=gcd(a,b)
这个时候X,Y的改变跨度一定比
而且关于X、Y的改变已经达到最小跨度,无法更小。
这是因为gcd(a,b)表示的是a和b的最大公约数,那么/gcd(a,b)就是相对应最小的,无法更小。
4.乘法逆元,拓展欧几里德求逆元
1.一般逆元
2.最小正乘法逆元
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int exgcd(int a,int b,int &X,int &Y)//采用引用&,从递归终点不断修改X,Y值
{
if(!b)
{
X=1,Y=0;
return a;
}
int ans=exgcd(b,a%b,X,Y);
int X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return ans;
}
int cal(int a,int m)//a*X=1(mod m);
{
int X,Y;
int gcd=exgcd(a,m,X,Y);
if(1%gcd) return -1;//此时方程无解
m=abs(m);//保证分母非负
int ans=X%m;
if(ans<=0) ans+=m;
return ans;
}
int main()
{
int a,m;
while(~scanf("%d%d",&a,&m))
{
printf("结果:\n%d\n",cal(a,m));
}
return 0;
}
3.a*X≡c(mod m)型
//a*X=c(mod m)
int cal(int a,int m,int c)
{
int X,Y;
int gcd=exgcd(a,m,X,Y);
if(c%gcd) return -1;
X*=c/gcd;
m/=gcd;
m=abs(m);
return (X%m+m)%m;
}
简单的题目:
1.ZOJ Problem Set - 3609
The modular modular multiplicative inverse of an integer a modulo m is an integer x such that a-1≡x (modm)
. This is equivalent toax≡1 (modm)
.
Input
There are multiple test cases. The first line of input is an integer T ≈ 2000 indicating the number of test cases.
Each test case contains two integers 0 < a ≤ 1000 and 0 < m ≤ 1000.
Output
For each test case, output the smallest positive x. If such x doesn't exist, output "Not Exist".
Sample Input
3 3 11 4 12 5 13
Sample Output
4 Not Exist 8
References
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk make_pair
#define _f first
#define _s second
/*
const double h=6.63*pow(10,-34);
const double c=3*pow(10,8);
const double u=1.660552*1e-27;
*/
using namespace std;
//const int INF= ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
//const int maxn= ;
//const int maxm= ;
//by yskysker123
ll exgcd(ll a,ll b,ll& X,ll &Y)
{
if(!b)
{
X=1,Y=0;
return a;
}
ll ans=exgcd(b,a%b,X,Y);
ll X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return ans;
}
ll cal(ll a,ll m)
{
ll X,Y;
ll gcd=exgcd(a,m,X,Y);
if(1%gcd) return 0;
m=abs(m);
ll ans=X%m;
if(ans<=0) ans+=m;
return ans;
}
int main()
{
ll a,m;
int T;scanf("%d",&T);
ll tmp;
while(T--)
{
scanf("%lld%lld",&a,&m);
if(!(tmp=cal(a,m) ) ) puts("Not Exist");
else printf("%lld\n",tmp);
}
return 0;
}
2.ZOJ Problem Set - 3593
There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at pointA at first and your aim is pointB. There are 6 kinds of operations you can perform in one step. That is to go left or right bya,b andc, here c always equals to a+b.
You must arrive B as soon as possible. Please calculate the minimum number of steps.
Input
There are multiple test cases. The first line of input is an integer T(0 <T ≤ 1000) indicates the number of test cases. ThenT test cases follow. Each test case is represented by a line containing four integers 4 integersA,B,a and b, separated by spaces. (-231 ≤A,B < 231, 0 <a,b < 231)
Output
For each test case, output the minimum number of steps. If it's impossible to reach pointB, output "-1" instead.
Sample Input
2 0 1 1 2 0 1 2 4
Sample Output
1 -1
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk make_pair
#define _f first
#define _s second
/*
const double h=6.63*pow(10,-34);
const double c=3*pow(10,8);
const double u=1.660552*1e-27;
*/
using namespace std;
//const int INF= ;
typedef long long ll;
const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
//const int maxn= ;
//const int maxm= ;
//by yskysker123
ll exgcd(ll a,ll b,ll &X ,ll &Y )
{
if(!b)
{
X=1,Y=0;
return a;
}
ll ans=exgcd(b,a%b,X,Y);
ll X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return ans;
}
ll cal(ll a,ll b,ll c)
{
ll X,Y;
ll gcd=exgcd(a,b,X,Y);
if(c%gcd) return -1;
X*=c/gcd;
Y*=c/gcd;
a/= gcd;
// a=abs(a);
b/= gcd;
// b=abs(b);
ll t=(Y-X)/(b+a);//可以认为y在以a的速度减小,X在以b的速度增加。注意a和b都是/l了gcd的,也可里认为是相遇问题。
ll ans=1e18;//之前ans初始化 值太小了,结果wa了
for(ll i=t-1;i<=t+1;i++)
{
ll tx=X+b*i;//可以这样理解tx和ty的正负代表了方向,长度为a的步子要么左走,要么右走,b同。
ll ty=Y-a*i;
ll tmp;
if(abs(ty)+abs(tx)==abs(tx+ty))//tx和ty同号(对于tx+ty=c情况下的判断方法),长度为a和b中的部分步子可以合并为1长度为c的步子
//且三者方向相同。
tmp=max( abs(ty),abs(tx) );
else //tx和ty异号
tmp=abs(ty-tx) ;//长度为a和b中的部分步子可以合并为1长度为c的步子,
//只不过a或b中1个和c 步子方向相同,另外一个与之方向相反。
ans=min(ans,tmp);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
ll A,B,a,b;
while(T--)
{
scanf("%lld%lld%lld%lld",&A,&B,&a,&b);
ll C=B-A;
ll tmp;
if((tmp=cal( a,b,C) )!=-1 ) printf("%lld\n",tmp);
else puts("-1");
}
return 0;
}
3.hdu 2669 Romantic
Romantic
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3932 Accepted Submission(s): 1630
The Birds is Fly in the Sky.
The Wind is Wonderful.
Blew Throw the Trees
Trees are Shaking, Leaves are Falling.
Lovers Walk passing, and so are You.
................................Write in English class by yifenfei
Girls are clever and bright. In HDU every girl like math. Every girl like to solve math problem!
Now tell you two nonnegative integer a and b. Find the nonnegative integer X and integer Y to satisfy X*a + Y*b = 1. If no such answer print "sorry" instead.
Each case two nonnegative integer a,b (0<a, b<=2^31)
77 51 10 44 34 79
2 -3 sorry 7 -3
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk make_pair
#define _f first
#define _s second
/*
const double h=6.63*pow(10,-34);
const double c=3*pow(10,8);
const double u=1.660552*1e-27;
*/
using namespace std;
//const int INF= ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
//const int maxn= ;
//const int maxm= ;
//by yskysker123
ll exgcd(ll a,ll b,ll &X,ll &Y)
{
if(!b)
{
X=1,Y=0;
return a;
}
ll gcd=exgcd( b,a%b,X,Y );
ll X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return gcd;
}
bool work(ll a,ll b,ll &X,ll &Y)
{
ll gcd= exgcd(a,b,X,Y);
if( 1%gcd ) return false;
X=(X%b+b)%b;
Y= (1-X*a)/b;
return true;
}
int main()
{
ll a,b, X,Y;
while(~scanf("%lld%lld",&a,&b))
{
if(!work(a,b,X,Y)) puts("sorry");
else printf("%lld %lld\n",X,Y);
}
return 0;
}
4. hdu 1576 A/B
A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3306 Accepted Submission(s): 2507
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
2 1000 53 87 123456789
7922 6060
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk make_pair
#define _f first
#define _s second
/*
const double h=6.63*pow(10,-34);
const double c=3*pow(10,8);
const double u=1.660552*1e-27;
*/
using namespace std;
//const int INF= ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
//const int maxn= ;
//const int maxm= ;
//by yskysker123
const ll P=9973;
ll exgcd(ll a,ll b,ll &X,ll &Y)
{
if(!b)
{
X=1,Y=0;
return a;
}
ll ans=exgcd(b,a%b,X,Y);
ll X1=X,Y1=Y;
X=Y1;
Y=X1-a/b*Y1;
return ans;
}
ll cal(ll a,ll m)
{
ll X,Y;
ll gcd=exgcd(a,m,X,Y);
m=abs(m);
X=(X%m+m)%m;
return X;
}
int main()
{
int T;
scanf("%d",&T);//已知A%9973,要求A/B%9973,等价于A*(B的逆元) %9973,只需求 B的逆元;
ll A,B;
while(T--)
{
scanf("%lld%lld",&A,&B);
ll t=cal( B,P);
printf("%lld\n",A*t%P );
}
return 0;
}