【题目太正式了我还怎么写ヾ|≧_≦|〃】
【很简要】
【参考文献:《算法导论》、白书、gty课件,LH课件】
[2016-08-13 ]
[2017-02-14 update (Valentine's Day就写这玩意?!]

 

  

 1.基础

【除法定理】:对于任何整数a和正整数n,存在唯一整数q和r,满足0<=r<n且a=qn+r

  WARN:C++中貌似不完全遵守这个东西,n认为是|n|,并且a为负时r可以为负

  这是算法导论上的说法,有很多资料上并不遵守r是正整数

 

  有用的式子: a%b=a-a/b*b 


 

 2.最大公约数

几条性质:gcd(a,b)=gcd(|a|,|b|)

     gcd(a,0)=|a|

     gcd(a,ka)=|a|  

     gcd(a,b)=gcd(b,a mod b) --->Euclid算法

     gcd(na,nb)=n*gcd(a,b) ---->Stein算法

     当k与b互为质数,gcd(ka,b)=gcd(a,b) ---->Stein算法

     gcd(a,b)是a与b的线性组合集{ax+by: x,y belong Z}中最小的元素

【Euclid算法、扩展欧几里德算法】

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

int lcm(int a,int b){return a/gcd(a,b)*b;}

void exgcd(int a,int b,int &d,int &x,int &y){
    if(!b) d=a,x=1,y=0;
    else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}

 

扩展欧几里得算法:

  求解 ax+by=gcd(a,b) 的解 (x0,y0)  ,满足|x0|+|y0|最小,可能为负

过程:

边界 b==0时 ,d=a,x=1,y=0式子成立;

知道b*x1+a%b*y1=gcd(a,b)的(x1,y1) , 求ax+by=gcd(a,b)的(x,y)

用a%b=a-⌊a/b⌋*b来替换
x1*b + y1*a - y1*⌊a/b⌋*b = gcd(a,b)
y1*a + (x1-y1*⌊a/b⌋)*b = gcd(a,b)

待定系数法
x=y1, y=x1-y1*⌊a/b⌋;

求解不定方程:

ax+by=c --> 如果 gcd(a,b) | c 同乘c/gcd(a,b)  

直线上的整点 

任意解:   (x0+kb',y0-ka') , a'=a/gcd(a,b)=lcm(a,b)/b   想象坐标系,加上lcm(a,b)后还是在直线上的整点

【Stein算法】(更相减损术改)

原文:可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。
改进:利用上面那个性质

优势:不用除法   高精/位运算都很方便

int stein(int a,int b){
  if(a==0||b==0) return a==0?b:a;
  if(a&1==0&&b&1==0) return 2*stein(a>>1,b>>1);
  if(a&1==0) return stein(a>>1,b);
  if(b&1==0) return stein(a,b>>1);
  return stein(min(a,b),abs(a-b));
}

 


 

  3.唯一分解定理

 一个比较好的分解质因子的写法,用了线性筛,保存lp[i]为数字i的最小质因子

唯一智障的缺点是必须先筛到n,所以n大时还是正常点筛sqrt(n)然后一个个质数试吧

 

bool notp[N];
int p[N],lp[N],lpnum[N];
void sieve(int n){
    for(int i=2;i<=n;i++){
        if(!notp[i]) p[++p[0]]=i,lp[i]=i,lpnum[i]=p[0];
        for(int j=1;j<=p[0]&&i*p[j]<=n;j++){
            notp[i*p[j]]=1;lp[i*p[j]]=p[j];lpnum[i*p[j]]=j;
            if(i%p[j]==0) break;
        }
    }
}
int e[N];
void fac(int x,int e[]){
    while(x!=1){
        int j=lpnum[x];
        while(x%p[j]==0) x/=p[j],e[j]++;
        printf("e %d %d\n",p[j],e[j]);
    }
}
void invfac(int x,int e[]){
    while(x!=1){
        int j=lpnum[x];
        while(x%p[j]==0) x/=p[j],e[j]--;
    }
}
View Code

相关文章: