一個數約數個數=全部素因子的次數+1的乘積
舉個例子就是48 = 2 ^ 4 * 3 ^ 1,因此它有(4 + 1) * (1 + 1) = 10個約數
****************************************************************************************************** 展轉相除 最大公約數 gcd(a,b): int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } 若是b大於a則第一次遞歸轉換a和b的值。 *************************************************************************************************** 最小公倍數 lcm(a,b): 利用gcd能夠求出兩個數a,b的最小公倍數數,有惟一分解定理得 a=p1^e1*p2^e2*...*pn^en; b=p1^f1*p2^f2*...*pn^fn; 則 gcd(a,b)=p1^min(e1,f1)*p2^min(e2,f2)*...*pn^min(en,fn); lcm(a,b)=p1^max(e1,f1)*p2^max(e2,f2)*...*pn^max(en,fn); 有gcd(a,b)*lcm(a,b)=a*b。若是把lcm寫成a*b/gcd(a,b),可能會所以丟掉很多分數——a*b可能會溢出!正確的寫法是先除後乘,即 a/gcd(a,b)*b。 ************************************************************************************************************* 素數帥選:對於不超過n的每個非負整數p,刪除2p,3p,4p,...,當處理完全部數以後,尚未被刪除的就是素數,若用vis[i]表示i已被刪除 memset(vis,0,sizeof(vis)); for(int i=2;i<=n;i++) for(int j=i*2;j<=n;j+=i) vis[j]=1; 改進: int m=sqrt(n+0.5); 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]=1; ******************************************************************************************************************* 擴展歐幾里德算法: 找出一對整數(x,y),使得ax+by=gcd(a,b)。這裏的x,y不必定是正數,也多是負數或0。例如gcd(6,15)=3,6*3-15*1=3,其中x=3,y=-1。這個 方程還有其餘解,如x=-2,y=1。 程序: void gcd(int a,int b,int &d,int &x,int &y){ if(!b){ d=a;x=1;y=0; }else{ gcd(b,a%b,d,y,x); y-=x*(a/b); } }
這個解的x就是a關於b的逆元ios
y就是b關於a的逆元算法
更通常的推論: 設a,b,c爲任意整數。若方程ax+by=c的一組整數解爲(x0,y0),則它的任意整數解均可以寫成(x0+kB,y0-kA),其中A=a/gcd(a,b),B=b/gcd(a,b), (若是gcd(a,b)=0,意味着或b等於0,能夠特殊判斷)k取任意整數。 設a,b,c爲任意整數,g=gcd(a,b),方程ax+by=g的一組解(x0,y0),則當c是g的倍數時ax+by=c的一組解是(x0c/g,y0c/g);當c不是g的整數倍時無整數解。 **************************************************************************************************************************** 同餘與模運算: (a+b)mod n=((a mod n)+(b mod n))mod n (a-b)mod n=((a mod n)-(b mod n)+n)mod n ab mod n=(a mod n)(b mod n) mod n 減法中a mod n可能小於b mod n,須要在結果加上n。乘法中(a mod n)(b mod n)有時可能會溢出須要用long long,例如: int mul_mod(int a,int b,int n){ a%=n;b%=n; return (int)((long long)a*b%n); } 大整數取模 輸入n,m,輸出n mod m。 把大整數寫成"自左向右"的形式:1234=((1*10+2)*10+3)*10+4,用前面的公式每步求模: scanf("%s%d",n,&m); int len=strlen(n); int ans=0; for(int i=0;i<len;i++) ans=(int)(((long long)ans*10+n[i]-'0')%m); printf("%d\n",ans); 冪取模 輸入a,n,m,輸出a^n mod m。 分治法對半遞歸計算: int pow_mod(int a,int n,int m){ if(n==0) return 1; int x=pow_mod(a,n/2,m); long long ans=(long long)x*x%m; if(n&1) ans=ans*a%m; return (int)ans; } 線性方程組 輸入a,b,n,解方程ax≡b(mod n)。 a≡b(mod n)表示a和b關於模n同餘,即a mod n=b mod n。ax≡b(mod n)的充要條件是a-b是n的整數倍。 這樣原方程就能夠理解爲ax-b是n的整數倍,設這個倍數爲y,則ax-b=ny,移項ax-ny=b,這就是前面的擴展歐幾里德。 當b=1時,ax≡1(mod n),此時方程的解稱爲a關於模n的逆。當gcd(a,n)=1時,該方程有惟一解;不然無解。
(a^b)%p=((a%p)^(e(p)+b%e(p)))%p 其中e(p)表示P的歐拉函數值
**************************************************************************************************************
除法取餘:
(a/b)%mod,當a,b很是大時沒法計算。
費馬小定理(Fermat Theory)是數論中的一個重要定理,其內容爲: 假如p是質數,且gcd(a,p)=1,那麼 a^(p-1)≡1(mod p)。即:假如a是整數,
p是質數,且a,p互質(即二者只有一個公約數1),那麼a的(p-1)次方除以p的餘數恆等於1。
能夠用乘法的逆來解決,固然可知當成定理來用(a/b)%mod=(a*b^(mod-2))%mod,mod爲素數
原理是費馬小定理:a^(mod-1)%mod=1,又a^0%mod=1,a^(mod-1)%mod=a^0%mod,兩邊同時乘a^(-1),因此a^(-1)=a^(mod-2),推出a/b=a*b^(-1)=a*b^(mod-2)數組
//質因數分解模板 #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; const int MAXN = 2000000; int prime[MAXN+1]; void getPrime()//求素數{ memset(prime,0,sizeof(prime)); for(int i = 2;i <= MAXN;i++){ if(!prime[i])prime[++prime[0]] = i; for(int j = 1;j <= prime[0] && prime[j] <= MAXN/i;j++){ prime[prime[j]*i] = 1; if(i % prime[j] == 0)break; } } } int factor[100][2];//factor[i][0]存素因子,factor[i][1]存素因子的個數 int fatCnt;//不重複的素因子個數 int getFactors(long long x) { fatCnt = 0; long long tmp = x; for(int i = 1; prime[i] <= tmp/prime[i];i++) { factor[fatCnt][1] = 0; if(tmp % prime[i] == 0 ) { factor[fatCnt][0] = prime[i]; while(tmp % prime[i] == 0) { factor[fatCnt][1] ++; tmp /= prime[i]; } fatCnt++; } } if(tmp != 1) { factor[fatCnt][0] = tmp; factor[fatCnt++][1] = 1; } return fatCnt; } int main() { getPrime(); int x; scanf("%d",&x); getFactors(x); return 0; }
//篩素數 const int MAXN = 1000000; int prime[MAXN+1]; void getPrime() { memset(prime,0,sizeof(prime)); for(int i = 2;i <= MAXN;i++) { if(!prime[i])prime[++prime[0]] = i; for(int j = 1;j <= prime[0] && prime[j] <= MAXN/i;j++) { prime[prime[j]*i] = 1; if(i % prime[j] == 0)break; } } }
//long long 數的素數斷定+質因數分解 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<ctime> #include<algorithm> using namespace std; typedef long long ll; const int S=20;//隨機算法斷定次數,S越大判錯機率越小 //計算(a*b)%c;a,b,c<2^63 ll mult_mod(ll a,ll b,ll c){ a%=c; b%=c; ll ret=0; while(b){ if(b&1){ ret+=a; ret%=c; } a<<=1; if(a>=c) a%=c; b>>=1; } return ret; } //計算(x^n)%c ll pow_mod(ll x,ll n,ll c){ if(n==1) return x%c; x%=c; ll tmp=x; ll ret=1; while(n){ if(n&1) ret=mult_mod(ret,tmp,c); tmp=mult_mod(tmp,tmp,c); n>>=1; } return ret; } //以a爲基,n-1=x*2^t a^(n-1)=1(mod n) 驗證n是否是合數 //必定是合數返回true,不必定返回false bool check(ll a,ll n,ll x,ll t){ ll ret=pow_mod(a,x,n); ll last=ret; for(int i=1;i<=t;i++){ ret=mult_mod(ret,ret,n); if(ret==1&&last!=1&&last!=n-1) return true; last=ret; } if(ret!=1) return true; return false; } // Miller_Rabin()算法素數斷定 //是素數返回true.(多是僞素數,但機率極小) //合數返回false; bool Miller_Rabin(ll n){ if(n<2) return false; if(n==2) return true; if((n&1)==0) return false; ll x=n-1; ll t=0; while((x&1)==0){ x>>=1; t++; } for(int i=0;i<S;i++){ ll a=rand()%(n-1)+1; if(check(a,n,x,t)) return false; } return true; } ll gcd(ll a,ll b){ if(a==0) return 1; if(a<0) return gcd(-a,b); while(b){ ll t=a%b; a=b; b=t; } return a; } //Pollard_rho質因數分解算法 ll factor[1000];//質因數分解結果(無序的) int tot;//質因數的個數,數組下標從0開始 ll Pollard_rho(ll x,ll c){ ll i=1,k=2; ll x0=rand()%x; ll y=x0; while(1){ i++; x0=(mult_mod(x0,x0,x)+c)%x; ll d=gcd(y-x0,x); if(d!=1&&d!=x) return d; if(y==x0) return x; if(i==k){ y=x0; k+=k; } } } //對n進行素因子分解 void findfac(ll n){ tot=0; if(Miller_Rabin(n)){//素數 factor[tot++]=n; return; } ll p=n; while(p>=n) p=Pollard_rho(p,rand()%(n-1)+1); findfac(p); findfac(n/p); } int main() { return 0; }
//歐拉函數是積性函數即 phi(ab) = phi(a) * phi(b) (a與b互質); //1~n中與n互質的整數和爲 n * phi(n) / 2 (n > 1); //sigma(d|n)phi(d) = n; //質數p和正整數k : phi(p^k) = p^k - p^(k - 1) = (p - 1) * p^(k - 1); // // #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int MAXN=1000000; ll c[100]; int n,prime[MAXN+10],mu[MAXN+10],phi[MAXN+10],tot; bool check[MAXN+10]; //組合 //性質:c(n,k)+c(n,k+1)=c(n+1,k+1); //根據c(n,k+1)=c(n,k)*(n-k)/(k+1) 能夠O(n)算出全部的。 void getC(){ c[0]=1; for(int i=0;i<n;i++) c[i+1]=c[i]*(n-i)/(i+1); } //擴展歐幾里得 void kgcd(ll a,ll b,ll &d,ll &x,ll &y) { if(!b){ d=a; x=1;y=0; }else{ kgcd(b,a%b,d,y,x); y-=x*(a/b); } } //計算模m下a的逆,若是不存在返回-1; ll inv(ll a,ll m) { ll d,x,y; kgcd(a,n,d,x,y); return d==1 ? (x+n)%n : -1; } //線篩素數 void get_prime(){ memset(check,0,sizeof(check)); tot=0; for(int i=2;i<=MAXN;i++){ if(!check[i]) prime[tot++]=i; for(int j=0;j<tot;j++){ if(i*prime[j]>MAXN) break; check[i*prime[j]]=1; if(i%prime[j]==0) break; } } } //線篩歐拉函數 void get_phi(){ memset(check,0,sizeof(check)); phi[1]=1; tot=0; for(int i=2;i<=MAXN;i++){ if(!check[i]){ prime[tot++]=i; phi[i]=i-1; } for(int j=0;j<tot;j++){ if(i*prime[j]>MAXN) break; check[i*prime[j]]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; }else{ phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } } //線篩莫比烏斯函數 void get_mu(){ memset(check,0,sizeof(check)); mu[1]=1; tot=0; for(int i=2;i<=MAXN;i++){ if(!check[i]){ prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot;j++){ if(i*prime[j]>MAXN) break; check[i*prime[j]]=1; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; }else{ mu[i*prime[j]]=-mu[i]; } } } } int main() { return 0; }