1、求最大公约数,最小公倍数;
int gcd(int x, int y){
if( 0==y ) return x;
else return gcd( y, x%y );
}
int lcm(int x, int y){
return x/gcd(x,y)*y;
}
2、素数筛选
//筛选法计算素数;最大范围1000000;
#define maxn 1000000 //计算范围;
bool isprime[maxn+10]; //标记是否为素数;
int prime[78500]; //记录素数;
void Prime(){
int i,i2,k;
for(i=1;i<=maxn+2;i+=2) isprime[i]=1,isprime[i-1]=0;
for(i=3;i<1000;i+=2){
if( isprime[i] == 1 ) {
i2=i+i, k=i*i;
while(k<=maxn) isprime[k]=0,k+=i2;
}
}
isprime[1]=0; isprime[2]=1; prime[1]=2; k=1;
for(i=3;i<=maxn;i+=2)
if(isprime[i]==1) prime[++k]=i;
prime[0]=k; //printf("k=%d\n",k);
}
/*
循环结束点 计算范围 素数个数
40 1000 prime[0]=168;
100 10000 prime[0]=1229;
50000 prime[0]=5311;
320 100000 prime[0]=9592;
1000 1000000 prime[0]=78498;
*/
3、取模运算
6 % 3 = 0;
19 % 10 = 9;
取模运算对 +, -, * 法具有封闭性,对除法不具有封闭性;
(x*y) % mod <==> (x%mod) * (y%mod) // 注意优先级;
(x+y) % mod <==> (x%mod) + (y%mod)
(x-y) % mod <==> (x%mod) - (y%mod)
// (76578908 * 28495857)% 107
《==》(76578908 % 107) *(28495857 % 107) ;
4、素因子分解
定理: 任意一个数(>1)可以唯一表示成若干个素因子的乘积;
60 = 2*2*3*5;
//整数的素因子分解, 不事先计算出素数,不保存因子幂;
//范围Maxn<=MAX_INT; 2147483647;
//2*3*5*7*11*13*17*19=9699690; 8个素因子;
//2*3*5*7*11*13*17*19*23=223092870; 9个素因子;
int fac[10]; //记录素因子;
void Divide(int x){
1int i,j,facnum=0;
for(i=2; i*i<=x; i++){
if( x%i==0 ){
while( x%i==0 ) x=x/i;
fac[++facnum]=i;
}
}
if(x!=1) fac[++facnum]=x;
fac[0]=facnum;
}
// 1000000007;
X = A*B; if( x%A==0 ) x%B==0;
60 = 5*12;
//整数的素因子分解并保存因子幂;不事先计算出素数;
//范围Maxn<=MAX_INT; 2147483647;
60 = 2*2*3*5;
60 = 2^2 * 3^1 * 5^1;
int fac[10]; //记录素因子;
int tnum[10]; //记录素因子的幂;
void Divide(int x){
int i,facnum=0;
for(i=2; i*i<=x; i++){
if(x%i==0){
int s=0;
while(x%i==0) x=x/i, s++;
fac[++facnum]=i, tnum[facnum]=s;
}
}
if(x!=1) fac[++facnum]=x, tnum[facnum]=1;
fac[0]=tnum[0]=facnum; //可以分解到的因子个数;
}
5、欧拉函数
一个数n,[1,n-1]内与之互素(最大公约数是1)的数的个数;比如 n= 8,那么 1, 3, 5, 7,这些数与之互素所以 euler[8]= 4;
如果一个数p是素数,则 euler[p]= p-1;
比如这一题: http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=10166#problem/D
(第五场比赛的题)
当然如果先预处理出素数的话,也可以求欧拉函数,会更快!
int Euler(int x){
int i,tmp=x;
for(i=1; i<=prime[0] && prime[i]*prime[i]<=tmp; i++){
if( tmp%prime[i]==0 ) {
x-= (x/prime[i]);
while( tmp%prime[i] == 0 ) tmp/= prime[i];
}
}
if(tmp>1) x-= x/tmp;
return x;
}
6、整数快速幂,矩阵快速幂;
这是重点,
在 http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=9834#problem/K (整数快速幂的讲解和标志代码,注释)
在 http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=9323#problem/D (矩阵快速幂的讲解和标志代码,注释)
不懂的来问,一定要看代码和讲解,注释,网上代码杂了,先看懂这两份再说了,当然看不看是自己的事;
3^12: 3*3*3*3....
3*3 = 9
3*3*3*3 = 9*9 = 81;
3^4 * 3^4 = 81*81;
7、约瑟夫环问题
http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=10166#problem/E
8、扩展欧几里德
a*x + b*y = 1; 可以得到这个方程的一个特解;
int Ext_gcd(int a,int b,int &x,int &y){
if(b==0) { x=1, y=0; return a; }
int res= Ext_gcd(b,a%b,y,x);
y-= a/b*x;
return res;
}
9、逆元
(a*b) = 1 (mod m),即 (a*b) % m = 1,
说明b是a对模数为m的逆元,a是b对模数为m的逆元;
记为inv[a].这等价于 a*inv[a]=k*p+1 ,k<a
例如 2*9%17=1, 2的逆元是9,9的逆元是2(mod p), 如果gcd(a,p)=1,则a的逆元存在. 以下设 gcd(a,p)=1;
逆元是积性函数,即 inv[ab] =inv[a]*inv[b];
当除法遇到取模运算时,要用到,比如求 (x/y)%m 的结果,
实际是求 ( x * Inv(y, m) ) % m;
求a对模m的逆元模版,如果返回-1,则逆元不存在;
int Inv(int a,int m){
int d,x,y;
d= Ext_gcd(a,m,x,y);
if(d==1) return (x%m+m)%m;
return -1;
}
10、若干数列
Fib数列,卡特兰数列,第二类stirling数……
http://www.cnblogs.com/liushang0419/archive/2011/10/06/2199722.html