标签:
几个重要需要记住的内容:
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