袁师兄数论模板

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值