数论

OI Summary —— Maths

by sro TXN orz

LATEX

扩展欧几里德(exgcd)#

模板题#

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

模板#

ax+by=c 有解的必要条件是 c0(modgcd(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的同余方程 ax1(modb) 的最小正整数解。

求法#

ax1(modb) 实质上就是 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;
}

乘法逆元#

定义#

ax1(modp),则称 xamodp 意义下的乘法逆元

模板题#

给定 n,p1n 中所有整数在模 p 意义下的乘法逆元。

费马小定理及求法#

p 为素数,a 为正整数且 ap 互质,则有 ap11(modp)

变形,得到:

aap21(modm)

x=ap2

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

阶乘线性求法#

invii!mod p 意义下的逆元

invi+1=1(i+1)!

invi+1(i+1)=1i!=invi

通过求出 invi+1 就可以递推出所有 invi

然后 1i(i1)!invi(modm)

模板 (阶乘线性求法)#

#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 的值,求出 Cn+mnmodp 的值, p 为质数。

求法#

Lucas(n,m,p)=Lucas(n/p,m/p,p)Cn mod pm mod 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)#

模板题#

给定 na1n m1n2n 个数,求出最小的 x 使得 xai(modmi) 对于 1in均成立

其中 x 为正整数且 ai 两两互质

求法#

假定 mul=1nmi Mi=mulmi Miti(modmi)

则我们可以构造出一个解 x=1naiMiti

任意解 x0=x+kM 对于 kZ

最小正整数解 xmin=x0modM

证明略

模板#

#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 个点 (xi,yi) 可以唯一地确定一个多项式 y=f(x)

现在告诉你这 n 个点,算出多项式f(x),并给定 kf(k)mod998244353

求法#

设基本多项式

g(x)=i=0,ijnxxixjxi

那么

f(x)=i=1nyig(x)

然后就可以在 O(n2) 的时间内求解

模板#

#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 满足 axb(modp) 其中 a,p 互质

求法#

假定 m=px=imj 其中 i,jm

原式可化为 aimjb(modp)

aimbaj(modp)

由于 a,p 互质,显然 a1p1modp 互不相同

我们枚举 j,将 bajmodp 存入 hash

然后枚举 i,从 hash 表里找出第一个 j 满足 aimbaj(modp)

此时 x=imj 即为所求

P3846 [TJOI2007] 可爱的质数/【模板】BSGS#

#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);
}

积性函数#

定义#

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

常见的积性函数#

d(n)n 的正因子数目

σ(n)n 的所有正因子之和

φ(n):欧拉函数

μ(n):莫比乌斯函数

性质#

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

莫比乌斯函数及反演#

莫比乌斯函数(Mobius Function)#

定义

n=1μ(n)=1

n=p1p2pk(其中 pi 为互异素数)μ(n)=(1)k

否则 μ(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];
		}
	}
}

莫比乌斯反演#

结论

{n=1  d|n μ(d)=1n>1  d|n μ(d)=0

[gcd(i,j)=1]=d|gcd(i,j) μ(d)

Miller Rabin 算法和Pollard-rho算法#

模板题#

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

求法#

这个求法有极小的概率错误,复杂度约为 O(p14)

Miller Rabin

前置定理:

  • 费马小定理:p 是质数,0<a<p,那么 ap11(modp)

  • 二次探测定理:对于 0<x<px21(modp) 有且仅有两解 : x=1x=p1

我们先找一个质数 q ,若 p=qp 为质数

然后根据费马小定理判断 qp11(modp) 是否成立,若不则 p 非质数

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

  • 先将 k 除以 2,然后用一个 t 记录下 pkmodx 的值。

  • 如果 t 不等于 1 且不等于 p1,则根据二次探测定理,x 非质数。

  • 如果 t=p1,则无法继续套用二次探测定理,因此直接返回 1

Pollard rho

前置知识:Miller Rabin 算法

我们构造一个函数 f(x)=(x2+c)moddoge 用来生成随机数,其中 c 是一个随机的常数

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

所以需要 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=1

z=a+bi (b0) 是一个虚数,b=0z为实数,a=0b0z 为纯虚数

四则运算#

x=a+biy=c+di

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

xy=(acbd)+(ad+bc)i

减法除法同理

复平面#

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

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

辐角:zx 轴正版轴夹角

模长:a2+b2

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

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

单位根#

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

表示法x=cos2kπn+sin2kπnik=1n

快速傅立叶变换(FFT)#

模板题#

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

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

模板#

// Problem: P3803 【模板】多项式乘法(FFT)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3803
// Memory Limit: 500 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>

using namespace std;

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}

const double pi=acos(-1.0);
const int N=8e6+5;

struct Complex
{
    double x,y;
    Complex (double a=0,double b=0){x=a,y=b;}
}f[N],g[N];

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[N];
int mx=1;

inline void fft(Complex *A,int op){
	for(int i=0;i<mx;++i)
		if(i<r[i]) swap(A[i],A[r[i]]);
	for(int mid=1;mid<mx;mid<<=1){
		Complex W(cos(pi/mid),op*sin(pi/mid));
		int R=mid<<1;
		for(int j=0;j<mx;j+=R){
			Complex w(1,0);
			for(int k=0;k<mid;++k,w=W*w){
				Complex x=A[j+k],y=w*A[j+mid+k];
				A[j+k]=x+y;
				A[j+mid+k]=x-y;
			}
		}
	}
}

signed main(){
	int n=read(),m=read();
	for(int i=0;i<=n;++i) f[i].x=read();
	for(int i=0;i<=m;++i) g[i].x=read();
	for(;mx<=n+m;mx<<=1,++l);
	for(int i=0;i<mx;r[i]=(r[i>>1]>>1|((i&1)<<l-1)),++i);
	fft(f,1),fft(g,1);
	for(int i=0;i<mx;++i) f[i]=f[i]*g[i];
	fft(f,-1);
	for(int i=0;i<=n+m;++i)
		printf("%d ",(int)(f[i].x/mx+0.5));
}

原根Primitive Root#

定义#

假若 gimodpgjmodp 对于  1i,jp1 均成立

则称 gp 的原根

存在原根的数#

p=1,2,4,a,2a,an 其中 a 为奇质数

求一个数的原根#

假如 gp 的原根,那么对于 gr1(modp) ,最小的 rp1 的约数

有关NTT特殊的数字#

{p=9982443533 , p1=998244352=223×7×17p=10045358093 , p1=1004535808=221×479

NTT#

暂时略

斯特林(Stirling)数#

第一类斯特林数#

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

s(n,m)=s(n1,m1)+s(n1,m)(n1)

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

生成函数:Fn(x)=i=0n1(xi) 其中 xi 的系数表示 s(n,i)

第二类斯特林数#

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

S(n,m)=S(n1,m1)+mS(n1,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)=2n11 S(n,n1)=Cn2

k=0nS(n,k)=Bn 其中 Bn 是贝尔数

通项公式S(n,m)=1m!(1)kCmk(mk)n

变式

允许空盒子ans=k=0mS(n,k)

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

盒子有差别且可为空ans=k=0m p(m,k)S(n,k)

倍尔数(Bell)数#

定义及求法#

Bn:把 n 个球放入若干个盒子的总方案数

Bn=k=0nS(n,k)

贝尔三角形#

1

1, 2

2, 3, 5

5, 7, 10, 15

15, 20, 27, 37, 52

52, 67, 87, 114, 151, 203

n 条的最后一个数是 Bnf(n,m)=f(n1,m)+f(n1,m1)

卡特兰(Catalan)数#

性质及求法#

1 1 2 5 14 42 132

Hn={k=0nHk1Hnk   if n>1   1   if n=0,1  

Hn=C2nnn+1

运用#

暂时略

下降/上升幂#

定义#

xn_=x(x1)(x2)(xn+1)=x!(xn)!=k=0ns(n,k)xk

xn¯=x(x+1)(x+2)(x+n1)=(x+n1)!(x1)!

作者:Into_qwq

出处:https://www.cnblogs.com/into-qwq/p/16445204.html

版权:本作品采用「qwq」许可协议进行许可。

posted @   Into_qwq  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示