其他分享
首页 > 其他分享> > 数论

数论

作者:互联网

目录

OI Summary —— Maths

\(\text{by sro TXN orz}\)

\(\LaTeX\)

扩展欧几里德(exgcd)

模板题

给定 \(a,b,c\) 求不定方程 \(ax+by=c\) 整数解

模板

\(ax+by=c\) 有解的必要条件是 \(c\equiv 0 \pmod{gcd(a,b)}\)

inline void exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-y*(a/b);
}

模板题变形

求关于$ x$的同余方程 $ a x \equiv 1 \pmod {b}$ 的最小正整数解。

求法

$ a x \equiv 1 \pmod {b}$ 实质上就是 \(ax+by=1\)

前提是 \(\gcd(a,b)=1\)

然后解

模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x,y;
inline void exgcd(ll m,ll n){
    if(!n){
        x=1;
        y=0;
        return;
    }
    exgcd(n,m%n);
    ll temp=y;
    y=x-m/n*y;
    x=temp;
    return;
}
int main(){
    ios::sync_with_stdio(false);
    ll a,b;
    cin>>a>>b;
    exgcd(a,b);
    cout<<(x%b+10*b)%b;
    return 0;
}

乘法逆元

定义

若 $a\cdot x \equiv 1 \pmod{p} $,则称 \(x\) 是 \(a\) 在 \(\bmod p\) 意义下的乘法逆元

模板题

给定 \(n,p\) 求 \(1\sim n\) 中所有整数在模 \(p\) 意义下的乘法逆元。

费马小定理及求法

若 \(p\) 为素数,\(a\) 为正整数且 \(a\) 、\(p\) 互质,则有 $a^{p-1}\equiv 1 \pmod{p} $

变形,得到:

\(a\cdot a^{p-2}\equiv 1 \pmod{m}\)

\(x=a^{p-2}\)

然后用快速幂求出即可,复杂度 \(O(n\log n)\)

阶乘线性求法

记 \(inv_i\) 为 \(i!\) 在 \(mod\ p\) 意义下的逆元

$inv_{i+1}=\frac{1}{(i+1)!} $

\(inv_{i+1}\cdot(i+1)=\frac{1}{i!}=inv_{i}\)

通过求出 \(inv_{i+1}\) 就可以递推出所有 \(inv_{i}\)

然后 $\frac{1}{i}\equiv (i-1)!\cdot inv_{i} \pmod{m} $

模板 (阶乘线性求法)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e6+5;
int frac[N],c[N];
int n,p;
inline void get_frac(){
    frac[0]=frac[1]=1;
    for(int i=2;i<=n;++i)
        frac[i]=frac[i-1]*i%p;
}
inline int qpow(int x,int idx){
    if(idx==0) return 1;
    int t=qpow(x,idx>>1);
    return idx&1?t*t%p*x%p:t*t%p;
}
inline int get_c(int x){
    return qpow(x,p-2)%p;
}
inline void get_fra_c(){
    c[n]=get_c(frac[n]);
    for(int i=n-1;i>=0;--i)
        c[i]=c[i+1]*(i+1)%p;
}
signed main(){
    scanf("%lld%lld",&n,&p);
    get_frac();
    get_fra_c();
    for(int i=1;i<=n;++i) printf("%lld\n",frac[i-1]*c[i]%p);
}

卢卡斯(Lucas)定理

模板题

给定整数 \(n, m, p\) 的值,求出 \(C_{n + m}^n \bmod p\) 的值, \(p\) 为质数。

求法

\(Lucas(n,m,p)=Lucas(n/p,m/p,p)\cdot \text{C}_{n\ \bmod\ p}^{m\ \bmod\ p}\)

\(Lucas(n+m,n,p)\) 为答案

递归写就行

模板

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,m,p;
int frac[N];
inline int qpow(int x,int idx){
	if(idx==0) return 1;
	int t=qpow(x,idx>>1);
	if(idx&1) return t*t%p*x%p;
	return t*t%p;
}
inline int C(int x,int y){
	if(x<y) return 0;
	return (frac[x]*qpow(frac[y],p-2))%p*qpow(frac[x-y],p-2)%p;
}
inline int Lucas(int x,int y){
	if(!y) return 1;
	return C(x%p,y%p)*Lucas(x/p,y/p)%p;
}
signed main(){
	ios::sync_with_stdio(0);
	int T;
	cin>>T;
	while(T--){
		cin>>n>>m>>p;
		frac[0]=1;
		for(int i=1;i<N;++i) frac[i]=frac[i-1]*i%p;
		cout<<Lucas(n+m,n)<<endl;
	}
}

中国剩余定理(CRT)

模板题

给定 \(n\) 和 \(a_{1\sim n}\) \(m_{1\sim n}\) 这 \(2\cdot n\) 个数,求出最小的 \(x\) 使得 $x \equiv a_i \pmod{m_i} $ 对于 \(\forall 1\le i\le n\)均成立

其中 \(x\) 为正整数且 \(a_i\) 两两互质

求法

假定 \(mul= {\textstyle \prod_{1}^{n}} m_i\) \(M_i=\frac{mul}{m_i}\) \(M_i \equiv t_i \pmod{m_i}\)

则我们可以构造出一个解 \(x= {\textstyle \sum_{1}^{n}a_i\cdot M_i\cdot t_i}\)

任意解 \(x_0=x+k*M\) 对于 \(\forall k\in Z\)

最小正整数解 \(x_{min}=x_0\bmod M\)

证明略

模板

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=100005;
int c[N],d[N];
int n,mul=1,ans;
inline void exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-y*(a/b);
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld%lld",&c[i],&d[i]);
        mul*=c[i];
    }
    for(int i=1;i<=n;++i){
        int l=mul/c[i];
        int x=0,y=0;
        exgcd(l,c[i],x,y);
        ans+=d[i]*l*(x<0?x+c[i]:x);
    }
    printf("%lld",ans%mul);
}

拉格朗日插值

模板题

\(n\) 个点 \((x_i,y_i)\) 可以唯一地确定一个多项式 \(y=f(x)\)

现在告诉你这 \(n\) 个点,算出多项式\(f(x)\),并给定 \(k\) 求 \(f(k)\bmod 998244353\)

求法

设基本多项式

\[g(x)={\textstyle \prod_{i=0,i\neq j}^{n}}\frac{x-x_i}{x_j-x_i} \]

那么

\[f(x)= {\textstyle \sum_{i=1}^{n}}y_i\cdot g(x) \]

然后就可以在 \(O(n^2)\) 的时间内求解

模板

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int N=2005;
int n,k,x[N],y[N],ans;
inline int qpow(int x,int idx){
	if(!idx) return 1;
	int t=qpow(x,idx>>1);
	return idx&1?t*t%mod*x%mod:t*t%mod;
}
inline int get_c(int x){
	return qpow(x,mod-2)%mod;
}
signed main(){
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",&x[i],&y[i]);
	}
	for(int i=1;i<=n;++i){
		int s1=y[i],s2=1;
		for(int j=1;j<=n;++j){
			if(j==i) continue;
			s1=s1*(k-x[j])%mod;
			s2=s2*(x[i]-x[j])%mod;
		}
		ans+=s1*get_c(s2)%mod;
        ans=(ans+mod)%mod;
	}
	printf("%lld",ans);
}

大步小步(BSGS)

模板题

给定 \(a,b,p\) 求最小 \(x\) 满足 \(a^x \equiv b \pmod{p}\) 其中 \(a,p\) 互质

求法

假定 $m=\left \lceil \sqrt{p} \right \rceil \(,\)x=i\cdot m-j$ 其中 \(i,j\leq m\)

原式可化为 \(a^{i\cdot m-j} \equiv b \pmod{p}\)

即 \(a^{i\cdot m} \equiv b\cdot a^j \pmod{p}\)

枚举 \(j\),将 \(b\cdot a^j\bmod p\) 存入 \(\textstyle{hash}\) 表

枚举 \(i\),从 \(\textstyle{hash}\) 表里找出第一个 \(j\) 满足 \(a^{i\cdot m} \equiv b\cdot a^j \pmod{p}\)

此时 \(x=i\cdot m-j\) 即为所求

模板

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a,b,p;
map <int,int> mp;
inline int qpow(int x,int idx){
	if(!idx) return 1;
	int t=qpow(x,idx>>1);
	if(idx&1) return t*t%p*x%p;
	return t*t%p;
}
inline int BSGS(){
	b%=p;
	int t=sqrt(p)+1;
	for(int i=0;i<t;++i)
		mp[b*qpow(a,i)%p]=i;
	a=qpow(a,t);
	if(!a) return !b?1:-1;
	for(int i=1;i<=t;++i){
		int v=qpow(a,i);
		if(mp.find(v)==mp.end()) continue;
		int j=mp[v];
		if(i*t-j>=0) return i*t-j;
	}
	return -1;
}
signed main(){
	scanf("%lld%lld%lld",&p,&a,&b);
	int ans=BSGS();
	if(ans==-1) puts("no solution");
	else printf("%lld\n",ans);
}

积性函数

定义

\(\forall a,b\) 互质,有 \(f(a\cdot b)=f(a)\cdot f(b)\) 的函数 \(f(x)\) 为积性函数

常见的积性函数

\(d(n)\):\(n\) 的正因子数目

\(\sigma(n)\):\(n\) 的所有正因子之和

\(\varphi(n)\):欧拉函数

\(\mu(n)\):莫比乌斯函数

性质

可以通过 \(f(a\cdot b)=f(a)\cdot f(b)\) 来线性筛

莫比乌斯函数及反演

莫比乌斯函数(Mobius Function)

定义

若 \(n=1\) 则 \(\mu(n)=1\)

若 \(n=p_1\cdot p_2\cdots p_k(\text{其中}\ p_i\ \text{为互异素数})\) 则 \(\mu(n)=(-1)^k\)

否则 \(\mu(n)=0\)

线性筛
int mu[N],prime[N],cnt;
bool vis[N];
inline void get_Mobius(int n){
	memset(vis,0,sizeof(vis));
	mu[1]=1;
	cnt=0;
	for(int i=2;i<=n;++i){
		if(!vis[i]){
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;++j){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0){
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
}

莫比乌斯反演

结论

\(\left\{\begin{matrix}n=1\ 时\ {\textstyle \sum_{d|n}}\ \mu(d)=1& \\n>1\ 时\ {\textstyle \sum_{d|n}}\ \mu(d)=0&\end{matrix}\right.\)

$[gcd(i,j)=1]= {\textstyle \sum_{d|gcd(i,j)}}\ \mu(d) $

Miller Rabin 算法和Pollard-rho算法

模板题

给定一个数 \(p\) 判断其是否为质数,若不是输出其最大因数

求法

这个求法有极小的概率错误,复杂度约为 \(O(p^{\frac14})\)

Miller Rabin

前置定理:

我们先找一个质数 \(q\) ,若 \(p=q\) 则 \(p\) 为质数

然后根据费马小定理判断 \(q^{p-1} \equiv 1 \pmod{p}\) 是否成立,若不则 \(p\) 非质数

否则,我们根据二次探测定理,先用一个 \(k\) 记录下 \(x-1\),然后只要 \(k\) 为偶数就持续操作:

Pollard rho

前置知识:Miller Rabin 算法

我们构造一个函数 \(f(x)=(x^2+c)\bmod doge\) 用来生成随机数,其中 \(c\) 是一个随机的常数

但这个方法构造出的随机数数列会有循环,就像一个 \(\rho\) 一样

所以需要 \(Floyd\) 判环,在有循环的时候重新随机一个 \(c\)

用这个方法生成随机数,然后加上 Miller Robin 的素数判断法就可以解决本题

模板

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
int n;
ll c;
ll mul(ll p,ll q,ll x){
	ll res=(long double)p/x*q;
	res%=x;
	return (p*q-res*x+x)%x;
}
ll getpow(ll a,ll p,ll x){
	ll res=1;
	while(p){
		if(p&1) res=mul(res,a,x);
		p>>=1;
		a=mul(a,a,x);
	}
	return res;
}
bool judge(ll a,ll x){
	ll p=x-1;
	while(!(p&1))
		p>>=1;
	ll cur=getpow(a,p,x);
	while(1){
		if(p==x-1){
			return cur==1;
		}
		ll nxt=mul(cur,cur,x);
		if(nxt==1){
			if(cur!=x-1 && cur!=1) return false;
		}
		cur=nxt;p<<=1;
	}
}
bool miller_rabin(ll x){
	if(x==2) return true;
	if(x==1) return false;
	int times=5;
	while(times--){
		ll a=rand()%(x-1)+1;
		if(!judge(a,x)) return false;
	}
	return true;
}
ll next_num(ll x,ll p){
	return (mul(x,x,p)+c)%p;
}
ll unsigned_abs(ll x){
	if(x<0) return -x;
	return x;
}
ll gcd(ll x,ll y)
{
	if(!x) return y;
	if(!y) return x;
	ll t=__builtin_ctzll(x|y);
	x>>=__builtin_ctzll(x);
	do
	{
		y>>=__builtin_ctzll(y);
		if(x>y) swap(x,y);
		y-=x;
	}while(y);
	return x<<t;
}
ll Pollard_rho(ll x){
	if(miller_rabin(x)) return x;
	if(x%2==0) return max(2ll,Pollard_rho(x/2));
	if(x%3==0) return max(3ll,Pollard_rho(x/3));
	if(x%5==0) return max(5ll,Pollard_rho(x/5));
	ll a=rand()%x;
	ll b=a;
	c=rand()%x;
	while(1){
		a=next_num(a,x);
		b=next_num(next_num(b,x),x);
		if(a==b){
			a=rand()%x;
			b=a;
			c=rand()%x;
			continue;
		}
		ll Gcd=gcd(unsigned_abs(a-b),x);
		if(Gcd!=1 && Gcd!=x)
			return max(Pollard_rho(x/Gcd),Pollard_rho(Gcd));
	}
}
void solve(ll x){
	if(miller_rabin(x)) printf("Prime\n");
	else printf("%lld\n",Pollard_rho(x));
}
int main(){
	srand(time(0));
	cin>>n;
	for(int i=1;i<=n;i++){
		ll x;
		scanf("%lld",&x);
		solve(x);
	}
}

复数

虚数定义及表示法

\(i=\sqrt{-1}\)

\(z=a+b\cdot i\ (b\neq0)\) 是一个虚数,\(b=0\) 时 \(z\)为实数,\(a=0\) 且 \(b\neq0\) 时 \(z\) 为纯虚数

四则运算

\(x=a+b\cdot i\),\(y=c+d\cdot i\)

\(x+y=(a+b)+(c+d)\cdot i\)

\(x\cdot y=(a\cdot c-b\cdot d)+(a\cdot d+b\cdot c)\cdot i\)

减法除法同理

复平面

每一个复数都对应平面直角坐标系的一个向量

\(z=a+b\cdot i\) 在复平面的向量坐标表示是 \((a,b)\)

辐角:\(z\) 与 \(x\) 轴正版轴夹角

模长:\(\sqrt{a^2+b^2}\)

加法的几何意义:两个向量相加

乘法的几何意义:辐角相加,模长相乘

单位根

定义:数学上,\(n\) 次单位根是 \(n\) 次幂为 \(1\) 的复数。它们位于复平面的单位圆上,构成正 \(n\) 边形的顶点,其中一个顶点是 \(1\) 。

表示法:\(x=\cos\frac{2k\pi}{n}+sin\frac{2k\pi}{n}\cdot i\),\(k=1\sim n\)

快速傅立叶变换(FFT)

模板题

给定一个 \(n\) 次多项式 \(F(x)\),和一个 \(m\) 次多项式 \(G(x)\)。

请求出 \(F(x)\) 和 \(G(x)\) 的卷积。

模板

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const double Pi=acos(-1.0);
struct complex
{
    double x,y;
    complex (double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN],b[MAXN];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}//不懂的看复数的运算那部分 
int N,M;
int l,r[MAXN];
int limit=1;
void FFT(complex *A,int type)
{
    for(int i=0;i<limit;i++) 
        if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列 
    for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
    {
        complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根 
        for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了 
        {
            complex w(1,0);//幂 
            for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分 
            {
                 complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应 
                A[j+k]=x+y;
                A[j+mid+k]=x-y;
            }
        }
    }
}
int main()
{
    int N=read(),M=read();
    for(int i=0;i<=N;i++) a[i].x=read();
    for(int i=0;i<=M;i++) b[i].x=read();
    while(limit<=N+M) limit<<=1,l++;
    for(int i=0;i<limit;i++)
        r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ;
    FFT(a,1);
    FFT(b,1);
    for(int i=0;i<=limit;i++) a[i]=a[i]*b[i];
    FFT(a,-1);
    for(int i=0;i<=N+M;i++)
        printf("%d ",(int)(a[i].x/limit+0.5));
    return 0;
}

原根Primitive Root

定义

假若 \(g^i\bmod p \neq g^j \bmod p\) 对于 \(\forall\ 1\leq i,j\leq p-1\) 均成立

则称 \(g\) 为 \(p\) 的原根

存在原根的数

\(p=1,2,4,a,2a,a^n\) 其中 \(a\) 为奇质数

求一个数的原根

假如 \(g\) 是 \(p\) 的原根,那么对于 $g^r \equiv 1 \pmod{p} $ ,最小的 \(r\) 是 \(p-1\) 的约数

有关NTT特殊的数字

\[\begin{cases} &{p=998244353 原根为3 \ ,\ p-1=998244352=2^{23}\times 7\times 17}\\ &{p=1004535809 原根为3 \ ,\ p-1=1004535808=2^{21}\times 479}\\ \end{cases} \]

NTT

暂时略

斯特林(Stirling)数

第一类斯特林数

\(s(n,m)\):\(n\) 个元素构成 \(m\) 个圆排列

\(s(n,m)=s(n-1,m-1)+s(n-1,m)\cdot(n-1)\)

n s(n,k)
n=0 1
n=1 0 1
n=2 0 1 1
n=3 0 2 3 1
n=4 0 6 11 6 1

生成函数:$F_n(x)= {\textstyle \prod_{i=0}^{n-1}(x-i)} $ 其中 \(x^i\) 的系数表示 \(s(n,i)\)

第二类斯特林数

\(S(n,m)\):把 \(n\) 个不同的球放进 \(m\) 个无差别的盒子中的方案数,盒子不为空

\(S(n,m)=S(n-1,m-1)+m\cdot S(n-1,m)\)

n S(n,k)
n=0 1
n=1 0 1
n=2 0 1 1
n=3 0 1 3 1
n=4 0 1 7 6 1

\(S(n,1)=1\) \(S(n,2)=2^{n-1}-1\) \(S(n,n-1)=C_n^2\)

$ {\textstyle \sum_{k=0}^{n}}S(n,k)=B_n $ 其中 \(B_n\) 是贝尔数

通项公式:\(S(n,m)=\frac{1}{m!}\cdot(-1)^k\cdot C_m^k\cdot(m-k)^n\)

变式

允许空盒子:\(ans={\textstyle \sum_{k=0}^{m}}S(n,k)\)

盒子有差别:\(ans=S(n,m)\cdot m!\)

盒子有差别且可为空:\(ans={\textstyle \sum_{k=0}^{m}}\ p(m,k)\cdot S(n,k)\)

倍尔数(Bell)数

定义及求法

\(B_n\):把 \(n\) 个球放入若干个盒子的总方案数

$B_n= {\textstyle \sum_{k=0}^{n}}S(n,k) $

贝尔三角形

1

1, 2

2, 3, 5

5, 7, 10, 15

15, 20, 27, 37, 52

52, 67, 87, 114, 151, 203

第 \(n\) 条的最后一个数是 \(B_n\) 且 \(f(n,m)=f(n-1,m)+f(n-1,m-1)\)

卡特兰(Catalan)数

性质及求法

1 1 2 5 14 42 132

\(H_n=\left\{\begin{matrix} &{\textstyle \sum_{k=0}^{n}}H_{k-1}\cdot H_{n-k}\ \ \text{ if } n>1\ \ \ \\ &1\ \ \text{ if } n=0,1\ \ \end{matrix}\right.\)

\(H_n=\frac{C_{2n}^n}{n+1}\)

运用

暂时略

下降/上升幂

定义

\(x^{\underline{n}}=x(x-1)(x-2)\cdots(x-n+1)=\frac{x!}{(x-n)!}={\textstyle \sum_{k=0}^{n}s(n,k)\cdot x^k}\)

\(x^{\overline{n}}=x(x+1)(x+2)\cdots(x+n-1)=\frac{(x+n-1)!}{(x-1)!}\)

标签:return,求法,数论,cdot,ll,int,模板
来源: https://www.cnblogs.com/into-qwq/p/16445204.html