數學的一些小知識
列舉因子法
bool judge(int n)
{
if(n==1) return false;
for(int i=2;i*i<=n;i++)
{
if(n%i==0) return false;
}
return true;
}
要把1特判掉。 可以1秒內單次判斷1~10^16以內的任意一個素數是否是素數
素數篩:提前處理1~N的全體素數,後可以直接判斷是否是素數
const int N=1000001; bool notprime[N]; void init() { notprime[1]=1; for(int i=2;i<N;i++) { if(notprime[i]==false) { for(int j=i+1;j<N;j=j+i) { notprime[j]=true; } } } }
mertens定理
https://wenku.baidu.com/view/c167c17931b765ce05081473.html看一波,嗯,這種東西看不懂還是要看的,不求甚解
可以一秒內10^7以內的質數和合數分離開來,接下來讓每個合數只刪除一次
尤拉篩(線性篩)每一個素數只被記錄一次,每一個合數只會被一個唯一的最小素因子標記一次。
https://wenku.baidu.com/view/4881881daaea998fcc220e99.html 原理還是可以看一下的
大致上講:每一個數有唯一的最大因子,被唯一篩去,唯一最大因子*小於等於最小質因子就是對應的合數,且篩全了
用了反證。
const int N=1000001; bool notprime[N]; int prime[N]; int pn; void init() { pn=0; notprime[1]=1; for(int i=2;i<N;i++) { for(notprime[i]==false) { prime[pn++]=i; } for(int j=0;j<pn;j++) { notprime[prime[j]*i]==true; if(i%prime[j]==0) break; } } }
1秒鐘處理從10^7~10^8
#include<algorithm>裡面有__gcd函式,注意要會用
最大公約數:
設兩數為a、b(a>b),用
表示a,b的最大公約數,r=a (mod b) 為a除以b的餘數,k為a除以b的商,即
。輾轉相除法即是要證明
。
第一步:令
,則設
第二步:根據前提可知
第三步:根據第二步結果可知,
也是
的因數
第四步:可以斷定
與
,則
,則
,則a與b的一個公約數
,故c非a與b的最大公約數,與前面結論矛盾,因此c也是b與r的最大公約數)從而可知
,繼而
。
證畢
注:以上步驟的操作是建立在剛開始時
的基礎之上的,即m與n亦互質。
百度上的解釋,海星,不用想了。
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
多個數求最大公約數
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int multi_gcd(int a[],int n)
{
int res=gcd(a[0],a[1]);
for(int i=2;i<n;i++)
res=gcd(res,a[i]);
return res;
}
最小公倍數略。
擴充套件歐幾里得演算法:
把這個實現和Gcd的遞迴實現相比,發現多了下面的x,y賦值過程,這就是擴充套件歐幾里德演算法的精髓。
可以這樣思考:
對於a'=b,b'=a%b 而言,我們求得 x, y使得 a'x+b'y=Gcd(a',b')
由於b'=a%b=a-a/b*b (注:這裡的/是程式設計語言中的除法)
那麼可以得到:
a'x+b'y=Gcd(a',b') ===>
bx+(a - a / b * b)y = Gcd(a', b') = Gcd(a, b) ===>
ay +b(x - a / b*y) = Gcd(a, b)
因此對於a和b而言,他們的相對應的p,q分別是 y和(x-a/b*y)
使用擴充套件歐幾里德演算法解決不定方程的辦法
對於不定整數方程pa+qb=c,若 c mod Gcd(a, b)=0,則該方程存在整數解,否則不存在整數解。
有種較為不嚴謹的方法證明,不過至少彌補了一點空白,望某些數論大師補充修改:
由於我們知道,存在一組x與y使得a*x+b*y=gcd(a,b)。
將等式兩邊同時乘以整數k,即a*x*k+b*y*k=gcd(a,b)*k。如果c mod gcd(a,b)=f,則0<=f<gcd(a,b)。
那麼可以令c=gcd(a,b)*k+f。這樣一來,就有a*x*k+b*y*k+f=c。
若f
0,由於f<gcd(a,b)<=a<=b(假設a<=b),所以不存在f=a*m(m為整數),也就不存在a*(x*k+m)+b*y*k=c。也就是說,不存在a*x+b*y=c的整數解x與y。
所以f=0,即只有當c mod gcd(a,b)=0時,a*x+b*y=c有正整數解。得證。
上面已經列出找一個整數解的方法,在找到p * a+q * b = Gcd(a, b)的一組解p0,q0後,p * a+q * b = Gcd(a, b)的其他整數解滿足:
p = p0 + b/Gcd(a, b) * t
q = q0 - a/Gcd(a, b) * t(其中t為任意整數)
至於pa+qb=c的整數解,只需將p * a+q * b = Gcd(a, b)的每個解乘上 c/Gcd(a, b) 即可,但是所得解並不是該方程的所有解,找其所有解的方法如下:
在找到p * a+q * b = Gcd(a, b)的一組解p0,q0後,可以
得到p * a+q * b = c的一組解p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b)),p * a+q * b = c的其他整數解滿足:
p = p1 + b/Gcd(a, b) * t
q = q1 - a/Gcd(a, b) * t(其中t為任意整數)
p 、q就是p * a+q * b = c的所有整數解。
上面是百度上的https://baike.baidu.com/item/擴充套件歐幾里德演算法/1053275?fr=aladdin比較透徹
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return d;
}
線性同餘方程,求逆元
int solve(int a,int b,int n)
{
int d=gcd(a,n);
if(b%d==0) return -1;
int k=b/d;
int x,y;
exgcd(a,n,x,y);
return x*k;
}
分解質因數
算術基本定理https://baike.baidu.com/item/算術基本定理/10920095?fr=aladdin
這個寫的通俗易懂,不錯。
預處理素數篩
int p[100];
int e[100];
int cnt;
int fenjie(int n)
{
cnt=0;
for(int i=0;i<pn&&prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
p[cnt]=prime[i];
while(n%prime[i]==0)
n/=prime[i];
e[cnt]++;
cnt++;
}
if(n>1) p[cnt]=n;
e[cnt++]=1;
}
}
快速冪
long long pow_mod(long long a,long long n,long long m)
{
long long res=1;
while(n>0)
{
if(n%2==1) res=res*a%m;
a=a*a%m;
n/=2;
}
return res;
}
費馬小定理
模素數是有迴圈節的,P-1
int getphi(int n)
{
int ans=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
ans-=ans/i;
while(n%i==0)
n/=i;
}
}
if(n>1) ans-=ans/n;
return ans;
}
https://baike.baidu.com/item/尤拉函式
baby step giant stephttps://www.cnblogs.com/wondove/p/7976525.html
不行了,看看其他人部落格吧