数学I-数论
前言
注:本文一切代码建立在此基础上
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll=long long;
using PI=pair<int,int>;
struct IO
{
char rbuf[1<<20],wbuf[1<<20],*p,*pp,*wp;
IO():p(rbuf),pp(rbuf),wp(wbuf){}
#define gc() (p==pp&&(pp=rbuf+fread(rbuf,1,1<<20,stdin),p=rbuf),p==pp?EOF:*p++)
#define pc(c) do{if(wp-wbuf==(1<<20))flush();*wp++=(c);}while(0)
IO&operator<<(char c){pc(c);return*this;}
IO&operator<<(const char*s){while(*s)pc(*s++);return*this;}
IO&operator>>(char*s){char c=gc();while(c<=32)c=gc();while(c>32)*s++=c,c=gc();*s='\0';return*this;}
template<typename T>IO&operator>>(T&x){x=0;char c=gc();bool f=0;while(c<'0'||c>'9')f|=(c=='-'),c=gc();while(c>='0'&&c<='9')x=x*10+(c^48),c=gc();if(f)x=-x;return*this;}
template<typename T>IO&operator<<(T x){if(x<0)pc('-'),x=-x;char t[30];int c=0;do{t[c++]=x%10+'0';}while(x/=10);while(c--)pc(t[c]);return*this;}
void flush(){if(wp>wbuf)fwrite(wbuf,1,wp-wbuf,stdout),wp=wbuf;}
~IO(){flush();}
}io;
#define cin io
#define cout io
一、整除与质数
1.1 整除基本性质
定义:\(a\mid b \iff \exists k\in\mathbb{Z},\ b=ak\)
| 性质 | 表述 | 证明思路 |
|---|---|---|
| 传递性 | \(a\mid b\land b\mid c\Rightarrow a\mid c\) | \(b=ak_1,c=bk_2\Rightarrow c=a(k_1k_2)\) |
| 线性组合 | \(a\mid b\land a\mid c\Rightarrow a\mid (xb+yc)\) | \(b=ak_1,c=ak_2\Rightarrow xb+yc=a(xk_1+yk_2)\) |
| 乘法保序 | \(a\mid b\Rightarrow ac\mid bc\ (c\neq0)\) | \(b=ak\Rightarrow bc=(ac)k\) |
| 大小约束 | \(a\mid b\land b\neq0\Rightarrow |a|\le|b|\) | \(b=ak\Rightarrow |b|=|a||k|\ge|a|\) |
1.2 质数判定:试除法优化
定理:若 \(n\) 为合数,则 \(\exists d\mid n,\ 2\le d\le\sqrt{n}\)
证明:设 \(n=ab,\ a\le b\),则 \(a^2\le ab=n\Rightarrow a\le\sqrt{n}\),取 \(d=a\) 即可。
代码实现(\(O(\sqrt{n})\),跳过偶数优化):
bool check(int n)
{
if(n<2) return 0;
if(n==2) return 1;
if(n%2==0) return 0;
for(int i=3;i*i<=n;i+=2)
if(n%i==0) return 0;
return 1;
}
易错点:
i*i<=n可能溢出,建议写i<=n/i或用long long- 特判 \(n=2\) 和偶数,减少一半循环
1.3 线性筛(欧拉筛)正确性证明
核心思想:每个合数 \(x\) 仅被其最小质因子筛掉一次。
算法流程:
const int N=1e7+5;
int pr[N],cnt;
bool vis[N];
void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) pr[++cnt]=i;
for(int j=1;j<=cnt&&i*pr[j]<=n;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0)break; // 关键:保证最小质因子
}
}
}
正确性证明:
- 每个合数都会被筛:设 \(x\) 最小质因子为 \(p\),则 \(x=p\cdot k\)。当外层循环到 \(k\) 时,内层枚举到 \(p\) 必筛 \(x\)。
- 每个合数只被筛一次:若 \(x\) 被 \(p_1\) 筛(\(p_1\) 最小质因子),则 \(x=p_1\cdot k_1\) 且 \(p_1\mid k_1\) 时
break,后续更大质因子不会再次筛 \(x\)。
复杂度:\(O(n)\),每个数进内层循环最多一次。
1.4 质因数分解(试除法 + 唯一分解定理)
唯一分解定理:\(\forall n>1,\ n=\prod_{i=1}^k p_i^{e_i}\),\(p_i\) 互异质数,表示唯一。
代码(\(O(\sqrt{n})\)):
vector<PI> fac;
for(int i=2;i*i<=n;i++)
if(n%i==0)
{
int c=0;
while(n%i==0) n/=i,c++;
fac.pb({i,c});
}
if(n>1)fac.pb({n,1}); // 剩余大质数
应用:求约数个数 \(\tau(n)=\prod(e_i+1)\),约数和 \(\sigma(n)=\prod\frac{p_i^{e_i+1}-1}{p_i-1}\)
例题:P2429 质数生成器
题目:求 \([L,R]\) 内所有质数,\(1\le L\le R\le 10^{12},\ R-L\le 10^6\)
思路:区间筛法(分段筛)
- 先筛出 \(\le\sqrt{R}\) 的所有质数
- 用这些质数去标记 \([L,R]\) 中的合数
const int M=1e6+5;
bool vis[M],seg[M];
int pr[M],cnt;
void init(int n) // 筛 sqrt(R) 内质数
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) pr[++cnt]=i;
for(int j=1;j<=cnt&&i*pr[j]<=n;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0)break;
}
}
}
void solve(ll L,ll R)
{
memset(seg,0,sizeof(seg));
if(L==1) seg[0]=1; // 1不是质数
for(int i=1;i<=cnt&&1ll*pr[i]*pr[i]<=R;i++)
{
ll st=max(1ll*pr[i]*pr[i],(L+pr[i]-1)/pr[i]*pr[i]);
for(ll j=st;j<=R;j+=pr[i]) seg[j-L]=1;
}
for(int i=0;i<=R-L;i++)
if(!seg[i]) cout<<L+i<<'\n';
}
二、最大公约数与扩展欧几里得
2.1 欧几里得算法
定理:\(\gcd(a,b)=\gcd(b,a\bmod b)\)
证明:设 \(d=\gcd(a,b)\),则 \(d\mid a,d\mid b\Rightarrow d\mid(a-qb)=a\bmod b\);反之同理,故两式公约数集合相同。
迭代实现(避免递归栈):
int gcd(int a,int b){while(b)a%=b,swap(a,b);return a;}
复杂度证明(拉梅定理):
- 最坏情况为斐波那契数列相邻项:\(\gcd(F_{k+1},F_k)\)
- 每次取模至少减半,故复杂度 \(O(\log\min(a,b))\)
2.2 扩展欧几里得
定理:\(\forall a,b\in\mathbb{Z},\ \exists x,y\in\mathbb{Z},\ ax+by=\gcd(a,b)\)
递归推导:
已知:b·x' + (a%b)·y' = gcd(b, a%b) = gcd(a,b)
展开:b·x' + (a - ⌊a/b⌋·b)·y' = gcd
整理:a·y' + b·(x' - ⌊a/b⌋·y') = gcd
故:x = y', y = x' - ⌊a/b⌋·y'
代码:
int exgcd(int a,int b,int&x,int&y)
{
if(!b){x=1,y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
通解结构:
若 \((x_0,y_0)\) 是 \(ax+by=c\) 的一组特解,\(d=\gcd(a,b)\),则通解为:
应用:解线性同余方程 \(ax\equiv c\pmod b\)
- 等价于 \(ax+by=c\)
- 有解 \(\iff d=\gcd(a,b)\mid c\)
- 特解 \(x_0\) 乘 \(\frac{c}{d}\),最小正整数解 \((x_0\cdot\frac{c}{d}\bmod\frac{b}{d}+\frac{b}{d})\bmod\frac{b}{d}\)
例题:P1516 青蛙的约会
题目:两只青蛙从 \(x,y\) 出发,每次跳 \(m,n\) 米,跑道长 \(L\),问何时相遇。
建模:求最小 \(t\ge0\) 使 \((x+mt)\equiv(y+nt)\pmod L\)
\(\Rightarrow (m-n)t\equiv(y-x)\pmod L\)
\(\Rightarrow (m-n)t+Lk=y-x\)
代码:
ll exgcd(ll a,ll b,ll&x,ll&y)
{
if(!b){x=1,y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
ll x,y,m,n,L,a,b,c,d,xx,yy;
cin>>x>>y>>m>>n>>L;
a=m-n;b=L;c=y-x;
if(a<0) a=-a,c=-c; // 保证a非负
d=exgcd(a,b,xx,yy);
if(c%d){cout<<"Impossible\n";return 0;}
ll t=xx*(c/d)%(b/d);
cout<<(t+b/d)%(b/d)<<'\n';
return 0;
}
三、同余与模运算
3.1 同余性质补充证明
可除性条件:\(ac\equiv bc\pmod m\Rightarrow a\equiv b\pmod{\frac{m}{\gcd(c,m)}}\)
证明:\(m\mid c(a-b)\),设 \(d=\gcd(c,m)\),则 \(\frac{m}{d}\mid\frac{c}{d}(a-b)\),而 \(\gcd(\frac{c}{d},\frac{m}{d})=1\),故 \(\frac{m}{d}\mid(a-b)\)。
3.2 快速幂原理与二进制分解
核心:\(a^b=\prod_{i:bit_i=1}a^{2^i}\)
迭代实现:
ll qpow(ll a,ll b,ll p)
{
ll res=1;
for(;b;b>>=1,a=a*a%p)
if(b&1) res=res*a%p;
return res;
}
复杂度:\(O(\log b)\),每轮平方 + 条件乘法
3.3 乘法逆元三种方法对比
| 方法 | 条件 | 复杂度 | 适用场景 |
|---|---|---|---|
| 费马小定理 | \(p\) 质数,\(p\nmid a\) | \(O(\log p)\) | 单点查询,模数固定质数 |
| 扩展欧几里得 | \(\gcd(a,m)=1\) | \(O(\log m)\) | 模数任意,单点查询 |
| 线性递推 | \(p\) 质数,求 \(1\sim n\) 逆元 | \(O(n)\) | 批量预处理 |
线性递推公式推导:
设 \(p=ki+r\ (0<r<i)\),则 \(ki+r\equiv0\pmod p\)
\(\Rightarrow r\equiv-ki\pmod p\)
\(\Rightarrow i^{-1}\equiv-k\cdot r^{-1}\equiv-\lfloor p/i\rfloor\cdot(p\bmod i)^{-1}\pmod p\)
代码:
inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p;
例题:P5431 逆元前缀和
题目:给定 \(n,p\),求 \(\sum_{i=1}^n i^{-1}\pmod p\),\(p\) 为质数。
思路:线性递推求逆元 + 前缀和
const int N=5e6+5;
ll inv[N],sum[N];
int n,p;
int main()
{
cin>>n>>p;
inv[1]=sum[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(p-p/i)*inv[p%i]%p;
sum[i]=(sum[i-1]+inv[i])%p;
}
cout<<sum[n]<<'\n';
return 0;
}
四、欧拉函数
4.1 定义与公式推导
定义:\(\varphi(n)=\|\{1\le k\le n:\gcd(k,n)=1\}\|\)
公式推导(容斥原理):
证明:从 \(1\sim n\) 中剔除所有 \(p\) 的倍数,对每个质因子 \(p\) 保留比例为 \(\frac{p-1}{p}\)。
积性证明:若 \(\gcd(a,b)=1\),则 \(\mathbb{Z}_{ab}^*\cong\mathbb{Z}_a^*\times\mathbb{Z}_b^*\)(中国剩余定理),故 \(\varphi(ab)=\varphi(a)\varphi(b)\)。
4.2 线性筛 \(\varphi\) 的更新规则推导
关键性质:
- 若 \(p\) 质数:\(\varphi(p)=p-1\)
- 若 \(p\mid i\):\(\varphi(ip)=\varphi(i)\cdot p\)(\(p\) 已在 \(i\) 的质因子中)
- 若 \(p\nmid i\):\(\varphi(ip)=\varphi(i)\cdot(p-1)\)(积性)
代码:
void init_phi(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
pr[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*pr[j]<=n;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0)
{
phi[i*pr[j]]=phi[i]*pr[j];
break;
}
else phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
}
4.3 扩展欧拉定理使用条件详解
定理:
注意:
- \(\gcd(a,m)\) 任意,不要求互质
- 仅当 \(b\ge\varphi(m)\) 时才加 \(\varphi(m)\),否则直接用 \(b\)
- 递归降幂时需判断指数大小
例题:P2568 GCD
题目:求 \(\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)\text{ is prime}]\)
推导:
代码:
const int N=1e7+5;
int phi[N],pr[N],cnt;
ll sum[N];
bool vis[N];
void init(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
{
pr[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*pr[j]<=n;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0)
{
phi[i*pr[j]]=phi[i]*pr[j];
break;
}
else phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+phi[i];
}
int main()
{
int n;
cin>>n;
init(n);
ll ans=0;
for(int i=1;i<=cnt;i++) ans+=2*sum[n/pr[i]]-1;
cout<<ans<<'\n';
return 0;
}
五、中国剩余定理
5.1 CRT 构造性证明
问题:解 \(x\equiv a_i\pmod{m_i}\),\(m_i\) 两两互质。
构造:
- \(M=\prod m_i\),\(M_i=M/m_i\)
- 求 \(t_i\equiv M_i^{-1}\pmod{m_i}\)(\(M_i\) 与 \(m_i\) 互质,逆元存在)
- \(x=\sum a_iM_it_i\pmod M\)
验证:对第 \(j\) 个方程,\(i\neq j\) 时 \(M_i\equiv0\pmod{m_j}\),仅 \(i=j\) 项贡献 \(a_jM_jt_j\equiv a_j\pmod{m_j}\)。
唯一性:若 \(x_1,x_2\) 均为解,则 \(x_1-x_2\equiv0\pmod{m_i}\ \forall i\),由互质性得 \(x_1\equiv x_2\pmod M\)。
5.2 EXCRT 两两合并推导
合并两个方程:
步骤:
- 设 \(x=a_1+m_1y\),代入得 \(m_1y\equiv a_2-a_1\pmod{m_2}\)
- 令 \(d=\gcd(m_1,m_2)\),有解 \(\iff d\mid(a_2-a_1)\)
- 用 exgcd 解 \(m_1y+m_2k=a_2-a_1\) 得特解 \(y_0\)
- 通解 \(y=y_0+t\cdot\frac{m_2}{d}\),代回得 \(x\equiv a_1+m_1y_0\pmod{\operatorname{lcm}(m_1,m_2)}\)
代码:
ll excrt(ll a[],ll m[],int k)
{
ll M=m[1],ans=a[1];
for(int i=2;i<=k;i++)
{
ll x,y,c=(a[i]-ans)%m[i];
if(c<0) c+=m[i];
ll d=exgcd(M,m[i],x,y);
if(c%d) return -1; // 无解
ll mod=m[i]/d;
x=(x*(c/d)%mod+mod)%mod;
ans+=M*x;
M*=mod;
ans%=M;
}
return (ans+M)%M;
}
例题:P4777 扩展中国剩余定理
注意:
- 使用
__int128或慢速乘防溢出 - 无解时返回 -1
ll mul(ll a,ll b,ll p) // 慢速乘防溢出
{
ll res=0;
for(;b;b>>=1,a=(a+a)%p)if(b&1)res=(res+a)%p;
return res;
}
ll exgcd(ll a,ll b,ll&x,ll&y)
{
if(!b){x=1,y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
ll excrt(ll a[],ll m[],int k)
{
ll M=m[1],ans=a[1];
for(int i=2;i<=k;i++)
{
ll x,y,c=(a[i]-ans)%m[i];
if(c<0) c+=m[i];
ll d=exgcd(M,m[i],x,y);
if(c%d) return -1;
ll mod=m[i]/d;
x=mul(x,c/d,mod);
ans+=mul(M,x,M*mod);
M*=mod;
ans%=M;
}
return (ans+M)%M;
}
六、莫比乌斯反演
6.1 狄利克雷卷积视角
定义:\((f*g)(n)=\sum_{d\mid n}f(d)g(\frac{n}{d})\)
关键函数:
- \(\varepsilon(n)=[n=1]\)(单位元)
- \(I(n)=1\)(常函数)
- \(\operatorname{id}(n)=n\)(恒等函数)
性质:\(\mu*I=\varepsilon\)(莫比乌斯反演核心)
6.2 反演公式推导
因数形式:
证明:
6.3 经典模型:\(\gcd\) 计数
问题:\(\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1]\)
推导:
整除分块优化:\(\lfloor\frac{n}{d}\rfloor\) 取值 \(O(\sqrt{n})\) 种,预处理 \(\mu\) 前缀和后 \(O(\sqrt{n})\) 计算。
例题:P3455 莫比乌斯反演+整除分块
题目:\(T\) 组询问,求 \(\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]\)
代码:
const int N=5e4+5;
int mu[N],sum[N],pr[N],cnt;
bool vis[N];
void init()
{
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
pr[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*pr[j]<N;j++)
{
vis[i*pr[j]]=1;
if(i%pr[j]==0)
{
mu[i*pr[j]]=0;
break;
}
else mu[i*pr[j]]=-mu[i];
}
}
for(int i=1;i<N;i++) sum[i]=sum[i-1]+mu[i];
}
ll solve(int n,int m)
{
if(n>m) swap(n,m);
ll res=0;
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
res+=1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
}
return res;
}
int main()
{
init();
int T;
cin>>T;
while(T--)
{
int a,b,c,d,k;
cin>>a>>b>>c>>d>>k;
ll ans=solve(b/k,d/k)-solve((a-1)/k,d/k)-solve(b/k,(c-1)/k)+solve((a-1)/k,(c-1)/k);
cout<<ans<<'\n';
}
return 0;
}
七、整除分块
7.1 取值种数与右端点公式证明
引理:\(\lfloor\frac{n}{i}\rfloor\) 的不同取值个数 \(\le 2\sqrt{n}\)
证明:
- 当 \(i\le\sqrt{n}\),最多 \(\sqrt{n}\) 种
- 当 \(i>\sqrt{n}\),\(\lfloor\frac{n}{i}\rfloor<\sqrt{n}\),最多 \(\sqrt{n}\) 种
右端点公式:对给定 \(l\),使 \(\lfloor\frac{n}{i}\rfloor\) 不变的最大 \(r=\lfloor\frac{n}{\lfloor n/l\rfloor}\rfloor\)
证明:设 \(q=\lfloor n/l\rfloor\),则 \(ql\le n<q(l+1)\)。
\(r\) 满足 \(qr\le n<q(r+1)\Rightarrow r\le n/q\),故 \(r=\lfloor n/q\rfloor\)。
7.2 多变量分块技巧
问题:\(\sum_{i=1}^n f(\lfloor\frac{n}{i}\rfloor,\lfloor\frac{m}{i}\rfloor)\)
技巧:右端点取 \(r=\min(\lfloor\frac{n}{\lfloor n/l\rfloor}\rfloor,\lfloor\frac{m}{\lfloor m/l\rfloor}\rfloor)\)
例题:P4213 杜教筛前置
题目:求 \(\sum_{i=1}^n\varphi(i)\),\(n\le10^{10}\)(需杜教筛,此处展示分块思想)
分块框架:
ll calc(int n)
{
ll res=0;
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
res+=1ll*(sum[r]-sum[l-1])*(n/l); // sum 为预处理前缀和
}
return res;
}
八、杜教筛
8.1 核心公式推导
目标:求 \(S(n)=\sum_{i=1}^n f(i)\)
构造:找 \(g\) 使 \(h=f*g\) 易求前缀和,则:
移项:
8.2 函数选择策略
| 目标 \(f\) | 辅助 \(g\) | \(h=f*g\) | \(S(n)\) 表达式 |
|---|---|---|---|
| \(\mu\) | \(I\) | \(\varepsilon\) | \(S_\mu(n)=1-\sum_{d=2}^n S_\mu(\lfloor n/d\rfloor)\) |
| \(\varphi\) | \(I\) | \(\operatorname{id}\) | \(S_\varphi(n)=\frac{n(n+1)}{2}-\sum_{d=2}^n S_\varphi(\lfloor n/d\rfloor)\) |
例题:P4213 杜教筛模板
// 预处理范围:N=5e6 时,时间≈0.5s,空间≈80MB
// 查询复杂度:$O(n^{2/3})$,哈希表记忆化避免重复计算
unordered_map<int,int>s_mu;
unordered_map<int,ll>s_phi;
int get_mu(int n)
{
if(n<N) return mu[n]; // 预处理部分直接返回
if(s_mu.count(n)) return s_mu[n];
int res=1; // ∑ε(i) = 1
for(int l=2,r;l<=n;l=r+1)
{
r=n/(n/l);
res-=(r-l+1)*get_mu(n/l); // g(d)=I(d)=1,系数为区间长度
}
return s_mu[n]=res;
}
九、组合数取模
9.1 阶乘逆元预处理细节
注意:
- 先求
fac[n],再用费马小定理求ifac[n],倒推ifac[i]=ifac[i+1]*(i+1)%p - 避免对每个
i单独求逆,复杂度 \(O(n+\log p)\)
9.2 Lucas 定理证明简述
定理:\(\binom{n}{m}\equiv\prod\binom{n_i}{m_i}\pmod p\),\(n_i,m_i\) 为 \(p\) 进制位
核心:\((1+x)^p\equiv1+x^p\pmod p\)(二项式系数 \(\binom{p}{k}\equiv0\ (0<k<p)\))
例题:P2480 古代猪文
题目:求 \(G^{\sum_{d\mid n}\binom{n}{d}}\bmod 999911659\)
思路:
- 模数 \(P=999911659\) 质数,指数对 \(P-1\) 取模(费马小定理)
- \(P-1=2×3×4679×35617\),对每个质因子用 Lucas 求组合数和
- EXCRT 合并结果,最后快速幂
代码框架:
ll p[4]={2,3,4679,35617},a[4];
ll calc(ll n,ll m,ll P) // Lucas 小模数版本
{
if(m>n) return 0;
ll res=1;
while(n)
{
ll ni=n%P,mi=m%P;
if(mi>ni) return 0;
for(int i=1;i<=mi;i++) res=res*(ni-i+1)%P*qpow(i,P-2,P)%P;
n/=P;m/=P;
}
return res;
}
int main()
{
ll n,G;
cin>>n>>G;
if(G%MOD==0){cout<<0<<'\n';return 0;} // 特判
for(int i=1;i*i<=n;i++)
if(n%i==0)
{
for(int j=0;j<4;j++) a[j]=(a[j]+calc(n,i,p[j]))%p[j];
if(i*i!=n)
for(int j=0;j<4;j++) a[j]=(a[j]+calc(n,n/i,p[j]))%p[j];
}
ll ans=excrt(a,p,4); // 合并指数
cout<<qpow(G,ans,MOD)<<'\n';
return 0;
}
十、阶与原根
10.1 阶的定义与性质
定义:设 \(a,n\) 互质,满足 \(a^k\equiv1\pmod n\) 的最小正整数 \(k\) 称为 \(a\) 模 \(n\) 的阶,记作 \(\operatorname{ord}_n(a)\)。
性质 1:若 \(a^m\equiv1\pmod n\),则 \(\operatorname{ord}_n(a)\mid m\)。
证明:设 \(k=\operatorname{ord}_n(a)\),由带余除法 \(m=qk+r\ (0\le r<k)\),则 \(a^m\equiv a^{qk+r}\equiv (a^k)^q a^r\equiv a^r\equiv1\),故 \(a^r\equiv1\),由 \(k\) 的最小性得 \(r=0\),所以 \(k\mid m\)。
性质 2:\(\operatorname{ord}_n(a)\mid\varphi(n)\)。
证明:由欧拉定理 \(a^{\varphi(n)}\equiv1\pmod n\),结合性质 1 即得。
10.2 原根的定义与存在性
定义:若 \(g\) 满足 \(\operatorname{ord}_n(g)=\varphi(n)\),则称 \(g\) 是模 \(n\) 的一个原根。
原根存在定理:模 \(n\) 存在原根当且仅当 \(n=2,4,p^k,2p^k\),其中 \(p\) 为奇质数,\(k\ge1\)。
(证明较复杂,本文从略)
10.3 原根的求法
步骤:
- 求出 \(\varphi(n)\) 的所有不同质因子 \(p_1,p_2,\dots,p_s\)。
- 从 \(2\) 开始枚举 \(g\),判断是否满足 \(g^{\varphi(n)/p_i}\not\equiv1\pmod n\) 对所有 \(i\) 成立。若成立,则 \(g\) 为原根。
正确性证明:若 \(g\) 不是原根,则存在 \(d<\varphi(n)\) 使 \(g^d\equiv1\),则 \(d\) 整除 \(\varphi(n)\),且存在某个质因子 \(p_i\) 使 \(d\mid\frac{\varphi(n)}{p_i}\),从而 \(g^{\varphi(n)/p_i}\equiv1\)。因此若所有 \(g^{\varphi(n)/p_i}\not\equiv1\),则 \(g\) 必为原根。
10.4 指标(离散对数)
若 \(g\) 是模 \(n\) 的原根,则每个与 \(n\) 互质的数 \(a\) 可唯一表示为 \(a\equiv g^{\operatorname{ind}_g(a)}\pmod n\),其中 \(0\le \operatorname{ind}_g(a)<\varphi(n)\),称为 \(a\) 关于 \(g\) 的指标。
性质:
- \(\operatorname{ind}_g(ab)\equiv\operatorname{ind}_g(a)+\operatorname{ind}_g(b)\pmod{\varphi(n)}\)
- \(\operatorname{ind}_g(a^k)\equiv k\cdot\operatorname{ind}_g(a)\pmod{\varphi(n)}\)
例题:P6091 【模板】原根
vector<int> get_factors(int x) // 求 x 的所有不同质因子
{
vector<int> fac;
for(int i=2;i*i<=x;i++)
if(x%i==0)
{
fac.pb(i);
while(x%i==0) x/=i;
}
if(x>1) fac.pb(x);
return fac;
}
bool has_root(int n) // 判断是否有原根
{
if(n==2||n==4) return 1;
vector<int> fac=get_factors(n);
if(fac.size()!=1&&fac.size()!=2) return 0; // 不是 p^k 或 2p^k 形式
if(fac.size()==2&&fac[0]!=2) return 0; // 2p^k 中第一个因子必须是2
return 1;
}
int get_root(int n)
{
if(!has_root(n)) return 0;
int phi=Phi(n); // 欧拉函数
vector<int> fac=get_factors(phi);
for(int g=2;g<n;g++)
{
if(gcd(g,n)!=1) continue;
int ok=1;
for(int p:fac)
if(qpow(g,phi/p,n)==1){ok=0;break;}
if(ok) return g;
}
return 0;
}
十一、二次剩余
11.1 定义与欧拉判别法
定义:设 \(p\) 为奇质数,\(a\) 与 \(p\) 互质。若存在 \(x\) 使得 \(x^2\equiv a\pmod p\),则称 \(a\) 是模 \(p\) 的二次剩余,否则称为二次非剩余。
欧拉判别法:
证明:
- 若 \(a\) 是二次剩余,即 \(a\equiv x^2\),则 \(a^{(p-1)/2}\equiv x^{p-1}\equiv1\pmod p\)(费马小定理)。
- 若 \(a\) 不是二次剩余,考虑 \(p\) 的简化剩余系,将其配对为 \((x,ax^{-1})\),每对乘积为 \(a\),且 \(x\neq ax^{-1}\)(否则 \(a\equiv x^2\))。共 \((p-1)/2\) 对,故 \(1\cdot2\cdots(p-1)\equiv a^{(p-1)/2}\pmod p\)。而左边为 \((p-1)! \equiv -1\pmod p\)(威尔逊定理),因此 \(a^{(p-1)/2}\equiv -1\)。
11.2 勒让德符号
定义勒让德符号 \(\left(\frac{a}{p}\right)=a^{(p-1)/2}\bmod p\),值为 \(1\) 或 \(-1\)。
性质:
- 完全积性:\(\left(\frac{ab}{p}\right)=\left(\frac{a}{p}\right)\left(\frac{b}{p}\right)\)
- 高斯引理:可用于计算 \(\left(\frac{2}{p}\right)=(-1)^{(p^2-1)/8}\)
11.3 Cipolla 算法求解二次剩余
问题:给定 \(p\)(奇质数)和 \(n\),求 \(x\) 使 \(x^2\equiv n\pmod p\)。
算法步骤:
- 若 \(n\equiv0\),返回 \(0\)。
- 若 \(n^{(p-1)/2}\equiv -1\),无解。
- 随机选取 \(a\) 使得 \(a^2-n\) 不是二次剩余,即 \((a^2-n)^{(p-1)/2}\equiv -1\)。
- 定义 \(\omega=\sqrt{a^2-n}\),在扩域 \(\mathbb{F}_p[\omega]\) 中计算 \((a+\omega)^{(p+1)/2}\),得到的结果即为一个解。
正确性证明:
- 在扩域中,\(\omega^2=a^2-n\)。
- 由 \((a+\omega)^p\equiv a^p+\omega^p\equiv a-\omega\)(因为 \(p\) 是奇质数,且 \(\omega^p=\omega\cdot(\omega^2)^{(p-1)/2}=\omega\cdot(-1)^{(p-1)/2}=-\omega\),因为 \((a^2-n)^{(p-1)/2}\equiv -1\))。
- 所以 \((a+\omega)^{p+1}\equiv (a+\omega)(a-\omega)\equiv a^2-(a^2-n)=n\)。
- 故 \(x=(a+\omega)^{(p+1)/2}\) 满足 \(x^2\equiv n\)。
例题:P5491 【模板】二次剩余
struct Complex
{
ll x,y; // x + y*ω
Complex(ll _x=0,ll _y=0):x(_x),y(_y){}
};
ll p,w; // w = a^2 - n
Complex mul(Complex a,Complex b)
{
ll xx=(a.x*b.x%p+a.y*b.y%p*w%p)%p;
ll yy=(a.x*b.y%p+a.y*b.x%p)%p;
return Complex(xx,yy);
}
Complex qpow_c(Complex a,ll b)
{
Complex res(1,0);
while(b)
{
if(b&1) res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
ll cipolla(ll n,ll p)
{
n%=p;
if(n==0) return 0;
if(qpow(n,(p-1)/2)!=1) return -1; // 无解
ll a;
while(1)
{
a=rand()%p;
w=(a*a%p-n+p)%p;
if(qpow(w,(p-1)/2)==p-1) break;
}
Complex res=qpow_c(Complex(a,1),(p+1)/2);
return res.x%p;
}
十二、离散对数与 BSGS
12.1 BSGS 算法(大步小步法)
问题:求解 \(a^x\equiv b\pmod p\),其中 \(\gcd(a,p)=1\),求最小非负整数 \(x\)。
算法原理:
令 \(x=im-j\),其中 \(m=\lceil\sqrt{p}\rceil\),\(0\le j<m\),则方程化为:
预处理所有 \(b\cdot a^j\) 存入哈希表,然后枚举 \(i\) 查找。
步骤:
- 计算 \(m=\lceil\sqrt{p}\rceil\)。
- 预处理 \(b\cdot a^j\ (0\le j<m)\) 的值与对应的 \(j\),存入哈希表(若有冲突取最大 \(j\))。
- 计算 \(t=a^m\bmod p\),令 \(cur=t\)。
- 枚举 \(i=1..m\),检查 \(cur\) 是否在哈希表中,若找到 \(j\),则 \(x=im-j\) 即为解。
复杂度:\(O(\sqrt{p})\) 时间,\(O(\sqrt{p})\) 空间。
12.2 扩展 BSGS
当 \(\gcd(a,p)\neq1\) 时,需处理。设 \(d=\gcd(a,p)\),若 \(d\nmid b\) 则无解;否则两边除以 \(d\),得到新方程,重复直到互质。最后用 BSGS 求解。
推导:
设 \(a^x\equiv b\pmod p\),令 \(d=\gcd(a,p)\)。
- 若 \(d=1\),直接 BSGS。
- 若 \(d>1\),若 \(b\not\equiv0\pmod d\) 则无解;否则令 \(a'=a/d,\ b'=b/d,\ p'=p/d\),方程化为 \(a^{x-1}\cdot a'\equiv b'\pmod{p'}\),即 \(a^{x-1}\equiv b'\cdot (a')^{-1}\pmod{p'}\),递归处理。
例题:P3846 [TJOI2007] 可爱的质数(BSGS 模板)
ll BSGS(ll a,ll b,ll p)
{
a%=p; b%=p;
if(b==1||p==1) return 0;
unordered_map<ll,ll> mp;
ll m=ceil(sqrt(p)),t=1;
for(int j=0;j<m;j++)
{
if(!mp.count(t)) mp[t]=j;
t=t*a%p;
}
ll base=qpow(a,p-1-m,p),cur=b;
for(int i=0;i<m;i++)
{
if(mp.count(cur)) return i*m+mp[cur];
cur=cur*base%p;
}
return -1;
}

浙公网安备 33010602011771号