数论
作者:互联网
- OI Summary —— Maths
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
前置定理:
-
费马小定理:\(p\) 是质数,\(0<a<p\),那么 \(a^{p-1} \equiv 1 \pmod{p}\)
-
二次探测定理:对于 \(0<x<p\),\(x^{2} \equiv 1 \pmod{p}\) 有且仅有两解 : \(x=1\) 和 \(x=p-1\)
我们先找一个质数 \(q\) ,若 \(p=q\) 则 \(p\) 为质数
然后根据费马小定理判断 \(q^{p-1} \equiv 1 \pmod{p}\) 是否成立,若不则 \(p\) 非质数
否则,我们根据二次探测定理,先用一个 \(k\) 记录下 \(x-1\),然后只要 \(k\) 为偶数就持续操作:
-
先将 \(k\) 除以 \(2\),然后用一个 \(t\) 记录下 \(p^{k}\bmod x\) 的值。
-
如果 \(t\) 不等于 \(1\) 且不等于 \(p-1\),则根据二次探测定理,\(x\) 非质数。
-
如果 \(t=p-1\),则无法继续套用二次探测定理,因此直接返回 \(1\)。
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