【數論初步】
阿新 • • 發佈:2019-02-06
一、歐幾里得 (連結)
1.歐幾里得演算法
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
2.擴充套件歐幾里得演算法
//先得到更底層的x2,y2,再根據計算好的x2,y2計算x1,y1。 //推理2,遞推關係 LL exgcd(LL a,LL b,LL &x,LL &y) { if(!b) { x=1;y=0; return a; } LL ret=exgcd(b,a%b,y,x); y-=a/b*x; return ret; }
3.貝祖等式
d0 是 a 和 b 的最大公約數。
在方程ax+by=m中,如果 m=m0d0,那麼方程顯然有無窮多個解:
(X0和Y0為擴充套件歐幾里得求出來的特解)
4.擴歐的乘法逆元
【逆元】設我們要求a/b%p的值,我們可以轉化為a*x%p。顯然,(1/b)%p=x%p,x*b%p=1。
前提:gcd(x,b)=1.這樣的話,x就存在。
如何求解a*x%n=1的方程呢?我們可以化成ax+ny=1,然後在上述gcd中帶出。(逆元:x=(x%p+p)%p;)
二、素數(連結)
1.尤拉函式
對正整數n,尤拉函式是小於或者等於n的數中與n互質的數的個數.
2.埃氏篩選(O(n*logn*logn))
const int N = 1e+6 + 7;
int pri[N],cnt;
bool isp[N];
void init_pri()
{
for(int i=2; i<N; i++)
if(!isp[i])
{
pri[++cnt]=i;
for(int j=i+i;j<N;j+=i)isp[j]=true;
}
}
3.尤拉篩選(O(n))
void init_pri(int n) { cnt=0; for(int i=2; i<=n; i++) { if(!isp[i]) pri[++cnt]=i; for(int j=1; j<cnt; j++) { long long k=1LL*i*pri[j]; if(k>n)break; isp[k]=true; if(i%pri[j]==0)break; } } }
4.Miller Rabbin(判斷大素數)
# define ll long long
ll mypow(ll a,ll b,ll m)
{
if(b==0)
return 1;
if(b==1)
return a%m;
ll temp=mypow(a,b/2,m);
temp*=temp;
temp%=m;
if(b&1)
temp*=a;
temp%=m;
return temp;
}
bool Miller_Rabbin(ll x)
{
if(x==2)
return true; ///2要直接判斷
for(int i=1;i<=50;++i){
ll a=rand()%(x-2)+2;
if(mypow(a,x-1,x)!=1)
return false;
}
return true;
}
int main()
{
ll n;
while(scanf("%lld",&n)!=EOF)
{
if(Miller_Rabbin(n))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
三、逆元 (連結)
1.費馬小定理:假如p是質數,且gcd(a,p)=1,那麼 a(p-1)≡1(mod p)。即:假如a是整數,p是質數,且a,p互質(即兩數只有一個公約數1),那麼a的(p-1)次方除以p的餘數恆等於1。當膜P為素數時有a^(p-1)=1(mod p) 那麼a^(p-2)=a^-1(mod p)
也就是說a的逆元為a^(p-2)。一般P較大時用快速冪求逆元。
typedef long long ll;
ll pow_mod(ll x, ll n, ll MOD)
{
ll ret=1;
while(n>0)
{
if(n&1)ret=ret*x%MOD;
x=x*x%MOD;
n>>=1;
}
return ret;
}
2.逆元打表
typedef long long LL;
const int N = 1e5 + 5;
int inv[N];
void inverse(int n, int p) {
inv[1] = 1;
for (int i=2; i<=n; ++i) {
inv[i] = (MOD - MOD / i) * inv[MOD%i] % MOD;
}
}
四、中國剩餘定理(連結)
1.當m1,m2,m3互質時
typedef long long LL;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1;y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL CRT(LL a[],LL m[],int n) /*模數為m,餘數為a x%m=a */
{
LL M=1,ans=0;
for(int i=1;i<=n;i++)M*=m[i];
for(int i=1;i<=n;i++)
{
LL x,y;
LL Mi=M/m[i];
exgcd(Mi,m[i],x,y);
ans=(ans+Mi*x*a[i])%M;
}
if(ans<0)ans+=M;
return ans;
}
2.線性同餘方程
typedef long long LL;
LL a[N],m[N]; /*模數為m,餘數為a x%m=a */
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
bool solve(LL &m0,LL &a0,LL m,LL a)
{
LL x,y;
LL gcd=exgcd(m0,m,x,y);
if((a-a0)%gcd)return false;
x*=(a-a0)/gcd;
x%=m/gcd;
a0=a0+x*m0;
m0*=m/gcd;
a0=(a0%m0+m0)%m0;
return true;
}
bool MLES(LL &m0,LL &a0,int n) /* 有解返回true,並且x=a0+k*m*/
{
bool flag=true;
m0=1;a0=0;
for(int i=1;i<=n;i++)
if(!solve(m0,a0,m[i],a[i]))
{
return false;
}
return true;
}