一些數論總結(Last update 10/19)
數論
By Misia in 2018
費馬小定理
若p是質數,a是任意整數,並且a不能被p整除,於是:
尤拉函式
OEIS A000010
φ(n)表示1~n以內和n互質的數的個數。
p表示n的所有質因數。
有
- 尤拉函式是積性函式,若m,n互質,則:
- 若n為奇數,則:
- 若n為質數,則:
線性篩尤拉函式
int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因數,p是素數,pt是素數個數
int get_phi(){
phi[1]=1;
int N=maxn,k;
for(int i=2;i<N;i++){
if(!m[i]){//i是素數
p[pt++]=m[i]=i,phi[i]=i-1;
}
for(int j=0;j<pt&&(k=p[j]*i)<N;j++){
m[k]=p[j];
if(m[i]==p[j]){//為了保證以後的數不被再篩,要break
phi[k]=phi[i]*p[j];
/*這裡的phi[k]與phi[i]後面的∏(p[i]-1)/p[i]都一樣(m[i]==p[j])只差一個p[j],就可以保證∏(p[i]-1)/p[i]前面也一樣了*/
break;
}
else{
phi[k]=phi[i]*(p[j]-1);//積性函式性質
}
}
}
}
尤拉定理
若 ,則:
更常用的:
原根
定義:設m>1, ,使得 成立的最小的r,稱為a對模m的階,記為 。
數m有原根的充要條件: (p為奇素數,k為任意正整數)。
定理
- 如果模m有原根,那麼它一共有 個原根。
- 若m>1, , ,則 。
- 如果p為素數,那麼素數p一定存在原根,並且p模的原根的個數為 。
- 設m是正整數,a是整數,若a模m的階等於 ,則稱a為模m的一個原根。
找原根
若欲求m的原根的話,對 進行質因數分解,求出所有質因子 ,若對於任意 ,均滿足 ,則g是m的原根。
求原根的程式碼
#include<bits/stdc++.h>
using namespace std;
int p[100007], c;
long long pow_mod(long long a,long long x,long long m){
long long ans=1;
while(x){
if(x&1){
ans=ans*a%m;
}
a=a*a%m;
x>>=1;
}
return ans;
}
bool ok(int x,int ph,int m){
for(int i=0;i<c;i++){
if(pow_mod(x,ph/p[i],m)==1){
return 0;
}
}
return 1;
}
void divide(int x){
c=0;
for(int i=2;i*i<=x;i++){
if(x%i==0){
p[c++]=i;
while(x%i==0){
x/=i;
}
}
}
if(x>1){
p[c++]=x;
}
}
int main(){
int wxh;
scanf("%d",&wxh);
while(wxh--){
int n;
scanf("%d",&n);
int m=n,ans=m;
for(int i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0){
n/=i;
}
}
}
if(n>1){
ans=ans/n*(n-1);
}
divide(ans);
int x=ans;
while(!ok(x,ans,m)){
x--;
}
printf("%d\n",x);
}
return 0;
}
二次剩餘
當存在某個x,式子
成立時,稱“d是模p的二次剩餘”。
當對任意x不成立時,稱“d是模p的二次非剩餘”。
學不來
關於如何計算二次剩餘,詳見Miskcoo的部落格
解方程a^b≡n(mod p)(p是素數)
一、已知n,p(p是奇數),b=2,求a
由費馬小定理:
根據尤拉準則,二次剩餘有解當且僅當
如果c滿足
不是p的二次剩餘,那麼
是方程
的解。因為有一半的數是非二次剩餘,所以可以隨機c,驗證即可。
詳見Philipsweng的部落格
二、已知n,p,a,求b
使用Baby-step giant-step演算法
(臨時)詳見Yuiffy的部落格
模板(Poj 2417)
#include<bits/stdc++.h>
using namespace std;
long long p,b,n;
void exgcd(long long c,long long d,long long &x,long long &y){
if(!d){
x=1;y=0;
return ;
}
exgcd(d,c%d,x,y);
long long z=y,r=x-(c/d)*y;
x=z;y=r;
}
void work(){
long long m=(long long)sqrt(p),bb=1,nn=n,inv,t;
map<int,int> num;
map<int,bool> app;
app[1]=1;
num[1]=0;
for(int i=1;i<=m-1;i++){
bb=bb*b%p;
if(!app[bb]){
app[bb]=1;
num[bb]=i;
}
}
bb=bb*b%p;
exgcd(bb,p,inv,t);
if(inv>0){
inv%=p;
}
else{
inv=inv%p+p;
}
for(int i=0;i<=m;i++){
if(app[nn]){
printf("%lld\n",i*m+num[nn]);
return;
}
nn=nn*inv%p;
}
printf("no solution\n");
}
int main(){
while(~scanf("%lld%lld%lld",&p,&b,&n)){
work();
}
return 0;
}
Ramsey定理
存在一個p,使得對p個點的完全圖紅藍染色,要麼存在n個點的紅色完全子圖,要麼存在m個點的藍色完全子圖。
把最小的p記作R(n,m),稱為Ramsey數,一般用到R(3,3)=6。
更大的Ramsey數特別難算。
第一類Stirling數
OEIS A008275(有符號)
表示將n個不同元素構成m個圓排列的方案數。
通俗來說,就是n個不同人圍m個相同圓桌而坐,要求各桌非空,其不同方案數。
第一類Stirling數又分為無符號(
)與有符號(
)兩種。
無符號
遞推式