标签:
【题目太正式了我还怎么写ヾ|≧_≦|〃】
【很简要】
【参考文献:《算法导论》、白书、天宇哥哥课件】
1.基础
【除法定理】:对于任何整数a和正整数n,存在唯一整数q和r,满足0<=r<n且a=qn+r
WARN:C++中貌似不完全遵守这个东西,n认为是|n|,并且a为负时r可以为负
【】
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|最小,可能为负
--> (x0+kb‘,y0-ka‘) a‘=a/gcd(a,b) //任意解(列等式推理)
ax+by=c --> if c%gcd(a,b)==0 -->(x0*c/g+kb‘,y0*c/g-ka‘) else no int solvement //直线上的整点
WARN: ax+by+c=0 c --> -c
【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.唯一分解定理(不说了)
4.素数1
【一个整数a>1只能被平凡约数1和自身所整除】
【判素数】:
(1)朴素
bool isP(int n){
if(n<=1) return false;
int m=sqrt(n)+1;
for(int i=2;i<=m;i++)
if(n%i==0) return false;
return true;
}
(2)Miller-Rabin(见下面)
【筛素数】:
(1)【Eratosthenes筛法】 复杂度O(nlogn)
[每一个质数筛掉它的倍数 一定有一个小于根号n的质因子]
const int N=1e9;
bool vis[N];
void era(int n){
int m=sqrt(n)+1;
memset(vis,0,sizeof(vis));
for(int i=2;i<=m;i++) if(!vis[i])
for(int j=i*i;j<=n;j+=i) vis[j]=true;
}
(2)【欧拉筛法】 复杂度O(n)
[对于任意一个合数,我们可以拆成最小质数*某个数字的形式。
我们枚举『某个数字』i(区分与埃氏筛法的枚举质因数),然后再从第一个质数开始枚举,进行筛选。
为了保证每个合数只被最小质因数筛选,当我们枚举的质数可以整除『某个数字』时,如果再往大里枚举,枚举的质数就不可能是最小质数了]
bool flag[N];
int prime[N];
int euler(int n){
int cntprime=0;
for(int i=2;i<=n;i++){
if(!flag[i]) prime[++cntprime]=i;
for(int j=1;j<=cntprime&&prime[j]*i<=n;j++){
flag[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
return cntprime;
}
5.同余、模
【符号太难打 不说了】
【+ - * 在%n时的性质太常用 不说了】
剩余系Zn:对于一个正整数n,一个整数集模n所得的余数域。[0,n-1]
[a]n={a+kn : k belong z} 包含a的模n等价类
Zn={[a]n : 0<=a<=n-1}={0,1,2,...,n-1}
----------
逆元:ax===1(mod n) x:a关于模n的逆元(inverse) ---------gcd(a,n)=1时唯一解,否则无解
同余系除法:乘以逆元
【解模线性方程】
ax===b(mod n) ------> ax-ny=b --->d=gcd(a,n)是b的约数则有解
------->直接用exgcd,然后x=x+k*(n/gcd(a,n))变正
------->(白书训练指南p126还有点东西 如恰好gcd(a,n)个解))
【求逆元】
同上
//ax===1(mod n) Zn:ax=1
//ax-ny=1 --> gcd(a,n)=1
//x -->all y that x===y(mod n)
int inv(int a,int n){
int d,x,y;
exgcd(a,n,d,x,y);
return d==1?(x+n)%n:-1; //we need x and x is probably -
}
6.素数2
【互质数】:两个整数a,b满足gcd(a,b)=1
【约数的个数】:对于n=p1^a1*p2^a2*...*pk^ak, 约数的个数=PI(ai+1):i=1..k=(a1+1)(a2+1)...(ak+1) <--乘法原理
【欧拉函数】:对于n=p1^a1*p2^a2*...*pk^ak,phi(n)=n(1-i/p1)(1-1/p2)...(1-i/pk) phi(1)=1 <--容斥原理+公式变形
-------------Zn* 缩系:小于n且与n互质 |Zn*|=phi(n)
【计算欧拉函数】:
(1) 单个 根号n求唯一分解算公式就行了
(2) 一片 类似素数筛发,找到一个素数把它的倍数(包括自己)乘上(i-1)/i
int phi(int n){
int m=sqrt(n+0.5);
int ans=n;
for(int i=2;i<=m;i++) if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) ans=ans/n*(n-1); //n self is prime
return ans;
}
const int N=1e6;
int a[N];
void initPhi(int n,int *phi){
for(int i=2;i<=n;i++) phi[i]=0;
phi[1]=1;
for(int i=2;i<=n;i++) if(!phi[i])
for(int j=i;j<=n;j+=i){
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
【素数定理】:pi(n) = n/ln n (略大)
【欧拉定理】: a^phi(n) === 1(mod n)
Zn+ 非零 --->if n is prime ->Zn+=Zn*
【费马定理】: 假如p is prime,且a p互质,则 a^(p-1) ===1(mod n)
--------------【求逆元】时 当n is prime,直接a^(n-2) %n
【Miller-Rabin】质数检测(太喜欢这个了 见下一篇文章)
标签:
原文地址:http://www.cnblogs.com/candy99/p/5765986.html