标签:
几个重要需要记住的内容:
1.欧几里得定理(辗转相除法)
int gcd(int a, int b){ return b==0?a:gcd(b, a%b); }
2.扩展欧几里得(求ax+by = gcd(a,b)的特解)
void e_gcd(LL a, LL b, LL &d, LL &x, LL &y){ if(b==0){ x = 1; y = 0; d = a; } else{ e_gcd(b, a%b, d, y, x); y-= x*(a/b); } }
3.中国剩余定理
同余方程组
x ≡ a1(mod m1)
x ≡ a2(mod m2)
... ...
x ≡ ak(mod mk)
方程组所有的解的集合就是:
#include <iostream>
using namespace std;
//参数可为负数的扩展欧几里德定理
void exOJLD(int a, int b, int &x, int &y){
//根据欧几里德定理
if(b == 0){//任意数与0的最大公约数为其本身。
x = 1;
y = 0;
}else{
int x1, y1;
exOJLD(b, a%b, x1, y1);
if(a*b < 0){//异号取反
x = - y1;
y = a/b*y1 - x1;
}else{//同号
x = y1;
y = x1 - a/b* y1;
}
}
}
//剩余定理
int calSYDL(int a[], int m[], int k){
int N[k];//这个可以删除
int mm = 1;//最小公倍数
int result = 0;
for(int i = 0; i < k; i++){
mm *= m[i];
}
for(int j = 0; j < k; j++){
int L, J;
exOJLD(mm/m[j], -m[j], L, J);
N[j] = m[j] * J + 1;//1
N[j] = mm/m[j] * L;//2 【注】1和2这两个值应该是相等的。
result += N[j]*a[j];
}
return (result % mm + mm) % mm;//落在(0, mm)之间,这么写是为了防止result初始为负数,本例中不可能为负可以直接 写成:return result%mm;即可。
}
int main(){
int a[3] = {2, 3, 2};
int m[3] = {3, 5, 7};
cout<<"结果:"<<calSYDL(a, m, 3)<<endl;
}
//直接求解欧拉函数 int euler(int n){ //返回euler(n) int res=n,a=n; for(int i=2;i*i<=a;i++){ if(a%i==0){ res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出 while(a%i==0) a/=i; } } if(a>1) res=res/a*(a-1); return res; } //筛选法打欧拉函数表 #define Max 1000001 int euler[Max]; void Init(){ euler[1]=1; for(int i=2;i<Max;i++) euler[i]=i; for(int i=2;i<Max;i++) if(euler[i]==i) for(int j=i;j<Max;j+=i) euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出 }
标签:
原文地址:http://www.cnblogs.com/topW2W/p/5361930.html