数论学习笔记

众所周知,tzc 不会数论(((

于是就来补题了(

同余与剩余系

同余与剩余系的概念

……感觉没啥必要写吧,但想想还是写了。

对于某个数 \(m\),若存在两数 \(a,b\) 满足 \(a\bmod m=b\bmod m\),我们就称 \(a,b\)\(m\) 同余,记作 \(a\equiv b\pmod{m}\)

显然同余有以下性质:

  1. \(a\equiv b\pmod{m}\)\(m\mid(a-b)\)
  2. \(a_1\equiv b_1\pmod{m},a_2\equiv b_2\pmod{m}\),则 \(a_1\pm a_2\equiv b_1\pm b_2\pmod{m}\)
  3. \(a\equiv b\pmod{m}\),则 \(ad\equiv bd\pmod{md}\)
  4. \(a\equiv b\pmod{m}\),则 \(\dfrac{a}{d}\equiv\dfrac{b}{d}\pmod{\dfrac{m}{\gcd(m,d)}}\)

由于这几条性质都比较显然就不放证明了。

对于某一集合 \(S\),记集合 \(T_m=\{x|x=y\bmod m,y\in S\}\)\(S\) 在模 \(m\) 下的剩余系。若 \(T_m\) 包含 \(0,1,2,\dots,m-1\) 中的所有数,那么就称其为模 \(m\) 意义下的完全剩余系。

斐蜀定理

咋感觉大家数论都是由二元不定方程引入的啊(

斐蜀定理讲的是这样一件事情:关于 \(x,y\) 的二元一次不定方程 \(ax+by=c\) 有解的充分必要条件是 \(c\)\(\gcd(a,b)\) 的倍数。

证明:必要性:考虑反证法,假设 \(c\) 不是 \(\gcd(a,b)\) 的倍数,\(x_0,y_0\) 为满足 \(ax+by=c\)\(x,y\)。设 \(d=\gcd(a,b),a'=\dfrac{a}{d},b'=\dfrac{b}{d}\),那么 \(ax_0+by_0=a'dx_0+b'dy_0=d(a'x_0+b'y_0)\) 也应为 \(d\) 的倍数,矛盾。

充分性:这里只讲一小部分。对于 \(c\)\(\gcd(a,b)\) 的倍数,我们只需找出 \(ax+by=\gcd(a,b)\)\(x,y\),再将其乘上 \(\dfrac{c}{\gcd(a,b)}\) 即可。至于 \(ax+by=\gcd(a,b)\) 的解怎样求,将会在下面扩展欧几里得的部分着重讲解。

扩展欧几里得(exgcd)

扩展欧几里得算法可用来解不定方程 \(ax+by=\gcd(a,b)\)

回顾求 \(a,b\) 的 gcd 的方法,若 \(b=0\),那么直接返回 \(a\),否则递归求解 \(\gcd(b,a\bmod b)\)

扩展欧几里得也是采用类似的做法,若 \(b=0\),那么 \(\gcd(a,b)=a\),原二元一次不定方程变为 \(ax=a\)\(x=1,y=0\) 即可。

\(b\neq 0\),递归求解不定方程 \(bx+(a\bmod b)y=\gcd(b,a\bmod b)\) 的解 \(x_0,y_0\)。根据求 \(\gcd\) 的过程可知 \(\gcd(a,b)=\gcd(b,a\bmod b)\),故 \(bx_0+(a\bmod b)y_0=\gcd(a,b)\),而 \(a\bmod b=a-\lfloor\dfrac{a}{b}\rfloor\times b\),故 \(bx_0+(a-\lfloor\dfrac{a}{b}\rfloor\times b)y_0=\gcd(a,b)\),整理一下可得 \(ay_0+b(x_0-\lfloor\dfrac{a}{b}\rfloor\times y_0)=\gcd(a,b)\),故方程 \(ax+by=\gcd(a,b)\) 的一组解为 \(x=y_0,y=x_0-\lfloor\dfrac{a}{b}\rfloor\times y_0\)。如此不断递归下去就可以得到原不定方程的解了。类似于数学中的归纳法。

上述过程同时也证明了斐蜀定理的充分性。

时间复杂度同辗转相除法,为 \(\mathcal O(\log(\max(a,b)))\)

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

逆元

回顾上面同余的各种性质,不难发现,\(a\)\(b\) 加、减、乘的结果在模意义下都可以直接得出。

那除法呢?我们不妨先看一个引例:\(a\equiv 3\pmod{5}\),并且 \(a\)\(2\) 的倍数,求 \(\dfrac{a}{2}\)\(5\) 余几。

显然 \(\dfrac{a}{2}\)\(5\)\(4\),因为 \(0,1,2,3,4\) 中只有 \(4\)\(2\) 倍模 \(5\)\(3\)

于是我们就有了逆元的定义,定义 \(a\)\(m\) 的逆元 \(a^{-1}\) 为满足 \(aa^{-1}\equiv 1\pmod{m}\)\(a^{-1}\),且 \(a^{-1}\in [0,m)\)

这样 \(\dfrac{x}{a}\equiv xa^{-1}\pmod{m}\) 因为 \(xaa^{-1}\equiv x\pmod{m}\)

显然 \(a\) 在模 \(m\) 下的逆元唯一。否则假设 \(\exist x,y\in[0,m)\) 满足 \(ax\equiv 1\pmod{m},ay\equiv 1\pmod{m}\),那么 \(x\equiv x(ay)=xay=(xa)y\equiv y\pmod{m}\),即 \(x\equiv y\pmod{m}\),而 \(x,y\in[0,m)\),矛盾!

那么是否所有数都有逆元呢?非也。还是看一个例子:\(a\equiv 4\pmod{6}\),并且 \(a\)\(2\) 的倍数,求 \(\dfrac{a}{2}\)\(6\) 余几。

这时候我们就很纠结了,因为 \(2,5\) 的两倍都模 \(6\)\(4\)。故我们无法知道 \(\dfrac{a}{2}\)\(6\) 究竟余几。

这个故事就告诉我们:\(2\) 在模 \(6\) 意义下没有逆元。

事实上对于所有 \((a,m)>1\)\(a\) 在模 \(m\) 意义下都没有逆元。否则假设 \(ab\equiv 1\pmod{m}\),设 \(d=\gcd(a,m),a=da',m=dm',ab=km+1\),那么 \(ab=da'b=km+1=kdm'+1\),即 \(1=da'b-kdm'=d(a'b-km')\),而 \(d>1\),矛盾!

求逆元一般有三种方法:

  1. 费马小定理,对于质数 \(p\),根据费马小定理(这个后面会提到)有 \(a^{p-1}\equiv 1\pmod{p}\),故 \(aa^{p-2}\equiv 1\pmod{p}\),即 \(a^{-1}\equiv a^{p-2}\pmod{p}\),这种方法只适用于 \(p\) 是质数的情况。
  2. exgcd,设 \(aa^{-1}=km+1\),那么 \(aa^{-1}-km=1\),相当于解二元一次不定方程 \(ax+my=1\),由于 \((a,m)=1\),故上面的方程等价于 \(ax+my=\gcd(a,m)\)。这个 exgcd 显然可以解决。最后提取 \(x\) 的值即可。注意,exgcd 不是基于剩余系的,故最后求出的 \(x\) 可能是负数,需通过取模操作将其处理到 \([0,m)\) 之内。
  3. 线性求逆元。设 \(inv_i\)\(i\) 在模 \(m\) 意义下的逆元,我们假设已经知道了 \(inv_1,inv_2,\dots,inv_{i-1}\) 的值,考虑怎样递推求出 \(inv_i\)。设 \(m=ki+r(r<i)\),于是 \(r\equiv -ki\pmod{m}\)。两边同时乘上 \(i^{-1}r^{-1}\) 可得 \(i^{-1}\equiv -kr^{-1}\pmod{m}\),而由于 \(r<i\),故 \(r^{-1}\) 我们已经事先求得了,可通过此式 \(\mathcal O(1)\) 递推得出 \(i^{-1}\)

中国剩余定理(CRT)

大概就是要求最小的满足

\[\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\\\dots\\x\equiv a_n\pmod{m_n}\end{cases} \]

的非负整数 \(x\),其中 \(m_1,m_2,\dots,m_n\) 两两互质。

要是早学 2 周就好了,WC2021 就能多个 20pts 了,就能 dd ymx 了(做白日梦 ing)

引理:在 \([0,m_1m_2\dots m_n)\) 中有且仅有一个满足条件的 \(x\)

证明:假设 \(\exist x_1,x_2\in[0,m_1m_2\dots m_n)\) 代入同余方程组均使方程组成立,根据同余的性质有 \(m_1\mid(x_1-x_2),m_2\mid(x_1-x_2),\dots,m_n\mid(x_1-x_2)\),即 \(\operatorname{lcm}(m_1,m_2,\dots,m_n)\mid(x_1-x_2)\),而 \(m_1,m_2,\dots,m_n\) 两两互质,故 \(\operatorname{lcm}(m_1,m_2,\dots,m_n)=m_1m_2\dots m_n\),于是有 \(m_1m_2\dots m_n\mid(x_1-x_2)\),而 \(x_1,x_2\in[0,m_1m_2\dots m_n)\),矛盾。而设 \(\{S=(b_1,b_2,\dots,b_n)|b_i=x\bmod m_i,x\in[0,m_1m_2\dots m_n)\}\),根据之前的证明过程可知不存在 \(x_1,x_2\in [0,m_1m_2\dots m_n)\) 满足 \((x_1\bmod m_1,x_1\bmod m_2,\dots,x_1\bmod m_n)=(x_2\bmod m_1,x_2\bmod m_2,\dots,x_2\bmod m_n)\),故 \(|S|=m_1m_2\dots m_n\),而满足 \(b_i<m_i\)\(n\) 元组总共只有 \(m_1m_2\dots m_n\) 个,故 \(S\) 中包含所有满足 \(b_i<m_i\)\(n\) 元组 \((b_1,b_2,\dots,b_n)\),故一定存在 \(x\in[0,m_1m_2\dots m_n)\) 能使同余方程组成立。

(以上全是我在瞎扯,不知道也没关系)

因此我们只需找出这个满足条件的 \(x\) 即可。

考虑设 \(P=\prod\limits_{i=1}^nm_i,x_i=\dfrac{P}{m_i}\)\(t_i\) 为满足 \(x_it_i\equiv 1\pmod{m_i}\)\(t_i\),再记 \(X=\sum\limits_{i=1}^na_ix_it_i\),那么 \(X\) 就是满足同余方程组的解了。如果题目要求最小解那就输出 \(X\bmod{m_1m_2\dots m_n}\) 即可。

为什么?考虑其中某一项 \(x\equiv a_i\pmod{m_i}\),对于 \(X\) 中的某一项 \(a_jx_jt_j(j\neq i)\),由于 \(x_j=\dfrac{P}{m_j}=\prod\limits_{k\neq j}m_k\)\(m_i\) 的倍数,故 \(a_jx_jt_j\equiv 0\pmod{m_i}\),也就是说 \(X\equiv a_ix_it_i\pmod{m_i}\),而 \(x_it_i\equiv 1\pmod{m_i}\),故 \(X\equiv a_i\pmod{m_i}\),满足条件。

至于怎样求这个 \(t_i\),由于 \(m_1,m_2,\dots,m_n\) 两两互质,\(x_i\)\(t_i\) 也是互质的,故 \(t_i\) 实质上就是 \(x_i^{-1}\pmod{m_i}\)。直接 exgcd 求逆元就行了。

模板题代码(注:两个 long long 相乘会爆,故需手写龟速乘):

const int MAXN=10;
int n;
ll ans=0,m[MAXN+2],a[MAXN+2],mul=1;
void exgcd(ll x,ll y,ll &a,ll &b){
	if(!y){a=1;b=0;return;}
	exgcd(y,x%y,a,b);ll tmp=a;a=b;b=tmp-x/y*b;
}
ll inv(ll a,ll mod){
	ll x,y;exgcd(a,mod,x,y);
	return (x+mod)%mod;
}
ll prod(ll a,ll b,ll mod){
	ll ret=0;
	for(;b;b>>=1,(a+=a)%=mod) if(b&1) (ret+=a)%=mod;
	return ret;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){scanf("%lld%lld",&m[i],&a[i]);mul*=m[i];}
	for(int i=1;i<=n;i++){
		ll iv=inv(mul/m[i],m[i]);//exgcd 求 x[i] 的逆元 t[i]
		ans=(ans+prod(prod(a[i],mul/m[i],mul),iv,mul))%mul;//龟速乘
	} printf("%lld\n",ans);
	return 0;
}

扩展中国剩余定理(exCRT)

还是求满足上式的最小整数 \(x\),只不过不再保证 \(m_1,m_2,\dots,m_n\) 两两互质。

考虑怎样将

\[\begin{cases}x\equiv a_1\pmod{m_1}\\x\equiv a_2\pmod{m_2}\end{cases} \]

两式合并为形如 \(x\equiv a\pmod{\operatorname{lcm}(m_1,m_2)}\) 的形式。

显然如果能解决两式合并的问题,那么本题就解决了。

考虑设 \(x=k_1m_1+a_1=k_2m_2+a_2\)

移个项可得 \(k_1m_1-k_2m_2=a_2-a_1\)

我们发现现在的条件是已知 \(m_1,m_2,a_2-a_1\),要求符合条件的 \(k_1,k_2\)

这不就喜闻乐见的 exgcd 吗?

根据斐蜀定理若 \(\gcd(m_1,m_2)\nmid (a_2-a_1)\),那么方程 \(k_1m_1-k_2m_2=a_2-a_1\),整个同余方程组就无解了。

否则假设 \(x,y\) 满足 \(xm_1+ym_2=\gcd(m_1,m_2)\),那么 \(k_1=\dfrac{x(a_2-a_1)}{\gcd(m_1,m_2)},k_2=-\dfrac{y(a_2-a_1)}{\gcd(m_1,m_2)}\) 符合条件,最后通过 \(x=k_1m_1+a_1\) 就可以合并两个方程组了。

int n;ll ans=0,lcm=1;
void exgcd(ll x,ll y,ll &d,ll &a,ll &b){
	if(!y){d=x;a=1;b=0;return;}
	exgcd(y,x%y,d,a,b);ll tmp=a;a=b;b=tmp-x/y*b;
}
ll prod(ll a,ll b,ll mod){
	a=(a%mod+mod)%mod;b=(b%mod+mod)%mod;
	ll ret=0;
	for(;b;b>>=1,(a+=a)%=mod) if(b&1) (ret+=a)%=mod;
	return ret;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		ll m,a;scanf("%lld%lld",&m,&a);
		ll x,y,gcd;exgcd(lcm,m,gcd,x,y);//找满足 xm[1]+ym[2]=gcd(m[1],m[2]) 的 x,y
		if(abs(a-ans)%gcd) assert(0);//如果 a[2]-a[1] 不是 gcd(m[1],m[2]) 的倍数那就无解
		ll new_m=m/gcd*lcm;x=prod(x,(a-ans)/gcd,new_m);//扩大 (a[2]-a[1])/gcd(m[1],m[2]) 倍
		ans=(ans+prod(x,lcm,new_m))%new_m;//x=k[1]m[1]+a[1]
		lcm=new_m;
	} printf("%lld\n",ans);
	return 0;
}

大步小步算法(BSGS)

北上广深(大雾)

大步小步算法可以用来解形如 \(a^x\equiv c\pmod{m}\) 的方程,其中 \(a\)\(m\) 互质。

考虑根号分治,设一个阈值 \(T\),假设 \(x=pT-q\),其中 \(p\geq 1,q\in [0,T)\)

那么 \(a^x=a^{pT-q}=(a^T)^p·a^{-q}\equiv c\pmod{m}\)

两边同时乘 \(a^q\) 可得 \((a^T)^p\equiv ca^q\pmod{m}\)

我们考虑这样一个算法:预处理时枚举 \(q\in [0,T)\) 并将 \(ca^q\) 压入哈希表中,再枚举 \(p\in[1,\dfrac{m}{T}]\) 并在哈希表中查询 \((a^T)^p\)

根据欧拉定理(这个在后面会讲)循环节的长度不会超过 \(\varphi(m)\),故枚举到 \(\dfrac{m}{T}\) 是没问题的。

时间复杂度 \(\sqrt{m}\),如果哈希表使用 std::map 会多个 log

const int MOD=19260817;
const int SQRT=1<<16;
int hd[MOD],nxt[SQRT+5],v[SQRT+5],id[SQRT+5],num=0;
void insert(int x,int t){
	v[++num]=x;id[num]=t;nxt[num]=hd[x%MOD];hd[x%MOD]=num;
}
int query(int val){
	for(int i=hd[val%MOD];i;i=nxt[i]) if(v[i]==val) return id[i];
	return -1;
}
int p,b,n;
int main(){
	scanf("%d%d%d",&p,&b,&n);int pw=1,pw2=1;
	for(int i=0;i<SQRT;i++){insert(n,i);n=1ll*n*b%p;pw=1ll*pw*b%p;}//将 ca^q 压入哈希表
	for(int i=1;i<=SQRT;i++){
		pw2=1ll*pw2*pw%p;
		if(~query(pw2)) return printf("%d\n",i*SQRT-query(pw2)),0;//如果存在就直接输出
	} printf("no solution\n");//无解
	return 0;
}

扩展大步小步算法(exBSGS)

还是解方程 \(a^x\equiv c\pmod{m}\),只不过不保证 \(a\)\(m\) 互质。

考虑分两种情况:

  1. 如果 \(\gcd(a,m)=1\) 那直接 BSGS 就行了。

  2. 如果 \(\gcd(a,m)>1\)

    \(d=\gcd(a,m),a=a'd,m=m'd\),我们提一个 \(a\) 出来,变成 \(a^{x-1}a'd\equiv c\pmod{m'd}\)

    显然 \(c\) 必须是 \(d\) 的倍数,否则就无解了。

    此时,根据同余第四条性质,我们可将同余方程左右两边以及模数都除以 \(d\),即 \(a^{x-1}a'\equiv\dfrac{c}{d}\pmod{m'}\)

    由于 \(d=\gcd(a,m)\),一定有 \(\gcd(a',m')=1\),故 \(a'\) 在模 \(m'\) 意义下的逆元一定存在。两边同乘 \(a'^{-1}\) 可得 \(a^{x-1}\equiv\dfrac{c}{d}·a'^{-1}\pmod{m'}\)

    发现又变成了 \(a^x\equiv c'\pmod{m'}\) 的形式。

    如果 \(a,m'\) 互质那直接上个 BSGS 就完事了。

    如果 \(a,m'\) 不互质那就继续递归下去。不难发现每次递归 \(m\) 至少减半,故递归层数最多 \(\log m\)

    注意在转化过程中可能出现 \(a=c\) 的情况,这时要及时停下来。

const int MOD=19260817;
const int SQRT=1<<16;
const int INF=-1e9;
int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
void exgcd(int x,int y,int &a,int &b){
	if(!y){a=1;b=0;return;}
	exgcd(y,x%y,a,b);int tmp=a;a=b;b=tmp-x/y*b;
}
int inv(int a,int mod){
	int x,y;exgcd(a,mod,x,y);
	return (x+mod)%mod;
}
struct hashtable{
	int v[SQRT+5],id[SQRT+5],nxt[SQRT+5],hd[MOD],num;
	void init(){for(int i=1;i<=num;i++) hd[v[i]%MOD]=0;num=0;}
	void insert(int x,int t){
		v[++num]=x;id[num]=t;nxt[num]=hd[x%MOD];hd[x%MOD]=num;
	}
	int query(int val){
		for(int i=hd[val%MOD];i;i=nxt[i]) if(v[i]==val) return id[i];
		return -1;
	}
} ht;
int BSGS(int a,int c,int p){
	ht.init();int mul=1,pw=1;
	for(int i=0;i<SQRT;i++){
		ht.insert(c,i);
		c=1ll*c*a%p;mul=1ll*mul*a%p;
	}
	for(int i=1;i<=SQRT;i++){
		pw=1ll*pw*mul%p;
		if(~ht.query(pw)) return i*SQRT-ht.query(pw);
	} return INF;
}
int solve(int a,int c,int p){
	if(a==c) return 1;//特判 a=c
	int d=gcd(a,p);
	if(d==1) return BSGS(a,c,p);//a,p 互质就直接 BSGS
	if(c%d) return INF;//如果 c 不是 gcd(a,m) 的倍数那就无解了
	return solve(a%(p/d),1ll*(c/d)*inv(a/d,p/d)%(p/d),p/d)+1;//递归求解
}
int main(){
	int a,p,b;
	while(~scanf("%d%d%d",&a,&p,&b)){
		if(!a||!p||!b) break;
		int ans=solve(a,b,p);
		if(ans==INF) printf("No Solution\n");
		else printf("%d\n",ans);
	}
	return 0;
}

卢卡斯定理(Lucas)

我们知道,当模数 \(p\) 为质数且比较大的时候,诸如 \(998244353\),那可以通过预处理阶乘逆元 \(\mathcal O(1)\) 计算组合数。

那如果 \(p\) 比较小呢?那就不能用这个算法了。因为对于 \(i\geq p\)\(i!\equiv 0\pmod{p}\),不存在逆元。

这时候就要用到 Lucas 定理了。Lucas 定理说的是这样一件事情:对于质数 \(p\)\(\dbinom{n}{m}\equiv\dbinom{n\bmod p}{m\bmod p}\dbinom{\lfloor\frac{n}{p}\rfloor}{\lfloor\dfrac{m}{p}\rfloor}\pmod{p}\)

简单证明一下吧:

考虑二项式定理 \((1+x)^p=\sum\limits_{i=0}^p\dbinom{p}{i}x^i\)

而对于 \(1\leq i\lt p\)\(\dbinom{p}{i}=\dfrac{p!}{i!(p-i)!}\equiv 0\pmod{p}\),因为 \(i!\)\((p-i)!\) 均不含因子 \(p\),无法抵消。

\((1+x)^p\equiv 1+x^p\pmod{p}\)

接下来考虑怎样计算 \(\dbinom{n}{m}\),显然 \(\dbinom{n}{m}=[x^m](1+x)^n\)

\(n,m\) 均看作一个 \(p\) 进制数,即 \(n=\sum\limits_{i=0}^ka_ip^i,m=\sum\limits_{j=0}^kb_ip^i\),其中 \(a_i,b_i\in [0,p)\)

那么 \((1+x)^n=\prod\limits_{i=0}^k(1+x)^{a_ip^i}\)

根据 \((1+x)^p\equiv 1+x^p\pmod{p}\) 可得 \((1+x)^{a_ip^i}=(1+x^{p^i})^{a_i}\)

\((1+x)^n=\prod\limits_{i=0}^k(1+x^{p^i})^{a_i}\)

而根据进制的性质,不同位之间的结果不会影响。

\(\dbinom{n}{m}=[x^m](1+x)^n=\prod\limits_{i=0}^k[x^{b_ip^i}](1+x^{p^i})^{a_i}=\prod\limits_{i=0}^k[x^{b_i}](1+x)^{a_i}=\prod\limits_{i=0}^k\dbinom{a_i}{b_i}\)

证毕。

知道了卢卡斯定理后就可以把 \(n,m\) 当作一个 \(p\) 进制数一位一位拆开并计算 \(\dbinom{a_i}{b_i}\),由于 \(a_i,b_i<p\),可用预处理阶乘逆元的方式计算 \(\dbinom{a_i}{b_i}\)。最后把结果乘起来就 ok 了。

扩展卢卡斯定理(exLucas)

真就啥都能扩展啊……

事实上 exLucas 和 Lucas 定理没有一点关系。

Lucas 定理可以计算 \(\dbinom{n}{m}\bmod{p}\),其中 \(p\) 是质数。如果 \(p\) 不是质数怎么办呢?就要用到 exLucas 了。

我们假设 \(p=p_1^{k_1}·p_2^{k_2}\dots p_x^{k_x}\),考虑计算其中每一项 \(\dbinom{n}{m}\bmod{p_i^{k_i}}\),然后 CRT 合并。

怎样计算 \(\dbinom{n}{m}\bmod p^k\),还是考虑将组合数拆开,写成 \(\dfrac{n!}{m!(n-m)!}\) 的形式。

回忆一下为什么这东西不能直接预处理阶乘逆元求,因为可能存在 \(i!\bmod p^k=0\) 的情况导致压根儿不存在逆元。

那如果我们把 \(n!\) 中的 \(p\) 因子都除掉呢?

假设 \(n!\) 中有 \(x\)\(p\) 因子,\(m!\) 中有 \(y\)\(p\) 因子,\((n-m)!\) 中有 \(z\)\(p\) 因子。

那么 \(\dfrac{n!}{m!(n-m)!}=\dfrac{\frac{n!}{p^x}}{\frac{m!}{p^y}·\frac{(n-m)!}{p^z}}\times p^{x-y-z}\)

显然 \(\dfrac{m!}{p^y},\dfrac{(n-m)!}{p^z}\) 均不含 \(p\) 因子,故它们都存在模 \(p^k\) 意义下的逆元。

因此如果我们知道 \(\dfrac{n!}{p^x},\dfrac{m!}{p^y},\dfrac{(n-m)!}{p^z},x,y,z\) 的值,就可以通过 exgcd 计算逆元+快速幂求出 \(\dfrac{n!}{m!(n-m)!}\bmod p^k\)。问题也就迎刃而解了。于是现在问题变为:

  1. 如何计算 \(\dfrac{n!}{p^x},\dfrac{m!}{p^y},\dfrac{(n-m)!}{p^z}\bmod p^k\) 的值
  2. 如何计算 \(x,y,z\) 的值。

先来解决第一个问题,我们将 \(1\sim n\) 中的数分成两部分,\(1·2·3·4\dots n=(1p·2p·3p\dots(\lfloor\dfrac{n}{p}\rfloor\times p))\times(1·2·3·4\dots(p-1)·(p+1)·(p+2)\dots·(2p-1)·(2p+1)·\dots)\) 即左边都是 \(p\) 的倍数,右边都不是 \(p\) 的倍数。

先考虑右边,显然右边所有数的乘积都会被计入 \(\dfrac{n!}{p^x}\),即 \((1·2·3·4\dots(p-1)·(p+1)·(p+2)\dots·(2p-1)·(2p+1)·\dots)\bmod p^k\)。不难发现这东西具有周期性,于是考虑将右边这玩意儿拆成若干个整段+最后零头部分来计算,整段的乘积显然可以扫一遍 \(i\in [1,p^k]\) 统计所有不是 \(p\) 的倍数的 \(i\) 的乘积。共有 \(\lfloor\dfrac{n}{p^k}\rfloor\) 个整段,快速幂一下即可,最后零头部分单独统计。这样就可求出 \((1·2·3·4\dots(p-1)·(p+1)·(p+2)\dots·(2p-1)·(2p+1)·\dots)\bmod p^k\) 了。

接下来考虑左边部分,由于它们都是 \(p\) 的倍数,故计入答案时都要除以 \(p\),也就变成求 \(1·2·3\dots\lfloor\dfrac{n}{p}\rfloor\) 除去所有 \(p\) 的因子之后的乘积,这个显然可以递归求出。将两部分一合并就是答案。

接下来解决第二个问题,知道第一个问题之后第二个问题就变得异常简单了,还是考虑将 \(1\sim n\) 的数分为两部分,显然右边部分的数是不会对 \(x\) 产生贡献的,左边 \(\lfloor\dfrac{n}{p}\rfloor\) 个数都会对 \(x\) 产生 \(1\) 的贡献,将左边所有数都除以 \(p\) 并递归 \((\lfloor\dfrac{n}{p}\rfloor)!\) 即可。于是我们有递推式 \(g(n)=\lfloor\dfrac{n}{p}\rfloor+g(\lfloor\dfrac{n}{p}\rfloor)\),递归算一算就好了。

ll n,m;int p;
void exgcd(int x,int y,int &a,int &b){
	if(!y){a=1;b=0;return;}
	exgcd(y,x%y,a,b);int tmp=a;a=b;b=tmp-(x/y)*b;
}
int inv(int a,int mod){
	int x,y;exgcd(a,mod,x,y);
	return (x+mod)%mod;
}
int qpow(int x,ll e,int mod){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%mod) if(e&1) ret=1ll*ret*x%mod;
	return ret;
}
int calc_f(ll n,int p,int pk){//计算 n!/p^x
	if(!n) return 1;int mul1=1,mul2=1;
	for(int i=1;i<=pk;i++) if(i%p) mul1=1ll*mul1*i%pk;//整段部分的乘积
	mul1=qpow(mul1,n/pk,pk);
	for(ll i=n/pk*pk+1;i<=n;i++) if(i%p) mul2=1ll*mul2*(i%pk)%pk;//零头部分
	return 1ll*calc_f(n/p,p,pk)*mul1%pk*mul2%pk;//递归计算左边部分
}
ll calc_g(ll n,int p){if(n<p) return 0;return calc_g(n/p,p)+(n/p);}
int main(){
	scanf("%lld%lld%d",&n,&m,&p);
	vector<pii> fac;int tmp=p;
	for(int i=2;i*i<=p;i++) if(tmp%i==0){
		int mul=1;
		while(tmp%i==0) tmp/=i,mul*=i;
		fac.pb(mp(i,mul));
	} if(tmp>1) fac.pb(mp(tmp,tmp));//预处理质因子
	int ans=0;
	for(int i=0;i<fac.size();i++){
		int x=fac[i].fi,y=fac[i].se;
		int f1=calc_f(n,x,y),f2=calc_f(m,x,y),f3=calc_f(n-m,x,y);
		int if2=inv(f2,y),if3=inv(f3,y);
		ll ex=calc_g(n,x)-calc_g(m,x)-calc_g(n-m,x);
		int rem=1ll*f1*if2%y*if3%y*qpow(x,ex,y)%y;//C(n,m) mod p^k
		int iv=inv(p/y,y);//CRT 合并
		ans=(ans+1ll*(p/y)*iv%p*rem%p)%p;
	} printf("%d\n",ans);
	return 0;
}

二次剩余

二次剩余的定义:对于正整数 \(p\),若正整数 \(x,n\in [0,p)\)\(x^2\equiv n\pmod{p}\),则称 \(x\)\(n\) 在模 \(p\) 意义下的二次剩余。(注:在 OI 中我们一般只探讨奇质数 \(p\) 的二次剩余问题,下文中若无特殊说明,默认 \(p\) 为奇质数)。

若存在整数 \(x\) 使得 \(x^2\equiv n\pmod{p}\) 那么我们就称 \(n\) 为模 \(p\) 意义下的二次剩余,否则称 \(n\) 为模 \(p\) 意义下的二次非剩余。

欧拉判别法

对于给定的正整数 \(n\),可用欧拉判别法判断关于 \(x\) 的同余方程 \(x^2\equiv n\pmod{p}\) 是否有解。

结论:\(n^{\frac{p-1}{2}}\bmod p=\begin{cases}1\to\text{有解}\\p-1\to\text{无解}\end{cases}\)

证明:

  1. 显然对于 \(p\nmid n\)\(n^{\frac{p-1}{2}}\equiv \pm 1\pmod{p}\),因为 \((n^{\frac{p-1}{2}})^2=n^{p-1}\equiv 1\pmod{p}\),而 \([1,p-1]\) 中只有 \(1\)\(p-1\) 的平方模 \(p\)\(1\)
  2. \(n\) 为模 \(p\) 意义下的二次剩余,记 \(c\) 为满足 \(x^2\equiv n\pmod{p}\)\(x\),那么根据费马小定理 \(n^{\frac{p-1}{2}}\equiv(c^2)^{\frac{p-1}{2}}=c^{p-1}\equiv 1\pmod{p}\)
  3. \(n\) 为模 \(p\) 意义下的二次非剩余,由于 \(p\nmid n\)\(p\) 为奇质数,故 \(\forall x\in[1,p-1],\exist y\in [1,p-1]\) 使得 \(xy\equiv n\pmod{p}\),并且这样的 \(y\) 也是唯一的。而 \(n\) 为模 \(p\) 意义下的二次非剩余,故不存在 \(x,y\) 满足 \(xy\equiv n\pmod{p}\)\(x=y\),故可将 \([1,p-1]\) 的中的数两两配对使得每一对中两数之积模 \(p\)\(n\)。计算这 \(\dfrac{p-1}{2}\) 对数的乘积可得 \(n^{\frac{p-1}{2}}\equiv (p-1)!\pmod{p}\)。那么 \((p-1)!\bmod p\) 是个什么东西呢?考虑计算 \(1\sim p-1\) 乘积的时候先单独将 \(1,p-1\) 拎出来,显然 \(\forall i\in[2,p-2],i^2\bmod p\neq 1\)。仿照刚才的分析过程可知 \(\forall x\in [2,p-2],\exist y\in [2,p-2]\) 满足 \(xy\equiv 1\pmod{p}\)\(x\neq y\),故 \((p-1)!\bmod p=1·(p-1)·1^{\frac{p-3}{2}}=p-1\),得证。(上述证明过程同时也证明了对于质数 \(p\) 都有 \((p-1)!\equiv p-1\pmod{p}\),这个定理有个专门的名字,叫什么威尔逊定理,不过名字啥的不重要啦)

还有一个小结论,那就是 \([1,p-1]\) 内二次剩余的的个数恰好为 \(\frac{p-1}{2}\),因为对于 \(x,y\in [1,p-1]\)\(x^2\equiv y^2\pmod{p}\) 等价于 \((x+y)(x-y)\equiv 0\pmod{p}\),而显然 \((x-y)\bmod p\neq 0\),故 \((x+y)\bmod p=0\),故可将 \(1\sim p-1\) 中的数分成 \(\frac{p-1}{2}\) 组使得每组中的两数都满足 \(x^2\equiv y^2\pmod{p}\) 并且不同组之间的数的平方模 \(p\) 不同余,得证。

求二次剩余的算法

欧拉判别法只能用来判定一个数是否存在二次剩余,那怎样求二次剩余呢?

首先有一个非常暴力的做法:由于 \(p\) 为奇质数,\(p\) 一定存在原根(这个后面会讲),暴力找出 \(p\) 的原根然后 BSGS 找出 \(g^a\equiv n\pmod{p}\),若 \(a\) 为奇数那无解,否则返回 \(g^{a/2}\) 即可,时间复杂度根号。

显然这个做法并不能让我们满足。下面讲一个更快的做法——Cipolla 算法。考虑随机在 \([0,p-1]\) 中产生一个数 \(a\),设 \(w=a^2-n\),那么如果 \(w\) 为模 \(p\) 意义下的二次非剩余,\((a+\sqrt{w})^{\frac{p+1}{2}}\) 就是满足条件的一个解。

证明:考虑 \((a+\sqrt{w})^p\) 的展开式,\((a+\sqrt{w})^p=\sum\limits_{i=0}^p\dbinom{p}{i}a^i(\sqrt{w})^{p-i}\)(有组合数学内味儿了),而 \(\dbinom{p}{i}\equiv 0\pmod{p}(i\in [1,p-1])\)(这个在证明 Lucas 定理的时候用到过,不记得了可以往前翻翻),故 \((a+\sqrt{w})^p\equiv a^p+(\sqrt{w})^p\pmod{p}\),而根据费马小定理 \(a^p=a·a^{p-1}\equiv a\pmod{p}\),而 \((\sqrt{w})^p=\sqrt{w}·(\sqrt{w})^{p-1}=\sqrt{w}·w^{\frac{p-1}{2}}\equiv-\sqrt{w}\pmod{p}\),故 \((a+\sqrt{w})^p\equiv a-\sqrt{w}\pmod{p}\),于是有 \((a+\sqrt{w})^{p+1}=(a+\sqrt{w})·(a+\sqrt{w})^p\equiv(a+\sqrt{w})(a-\sqrt{w})=a^2-w=(a^2-(a^2-n))=n\pmod{p}\),故 \((a+\sqrt{w})^{\frac{p+1}{2}}\) 为满足 \(x^2\equiv n\pmod{p}\)\(x\)

但你可能会疑惑:\(w\) 不是模 \(p\) 意义下的二次非剩余吗?哪儿来的 \(\sqrt{w}\) 啊?其实这玩意儿相当于扩展了数集的定义。我们记 \(\mathbb{Z}_w=\{a+b\sqrt{w}|a,b\in[1,p-1]\}\),在此基础上定义了乘法运算 \((a+b\sqrt{w})(c+d\sqrt{w})=(ac+bdw)+(ad+bc)\sqrt{w}\),类似于复数的乘法运算,可通过手写复数类+快速幂来实现计算 \((a+\sqrt{w})^{\frac{p+1}{2}}\)

由于那就是 \([1,p-1]\) 内二次剩余的的个数恰好为 \(\frac{p-1}{2}\),故期望随机的次数为 \(2\),总复杂度 \(\log p\)

int n,mod,w;
unsigned int rng60(){
	static unsigned int seed=19260817;
	seed^=seed<<17;seed^=seed<<10;seed^=seed>>7;
	return seed;
}
int qpow(int x,int e){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%mod) if(e&1) ret=1ll*ret*x%mod;
	return ret;
}
struct comp{
	int x,y;
	comp(){x=y=0;}
	comp(int _x,int _y){x=_x;y=_y;}
	comp operator *(const comp &rhs){
		return comp((1ll*x*rhs.x+1ll*y*rhs.y%mod*w%mod)%mod,(1ll*x*rhs.y+1ll*y*rhs.x)%mod);
	}
};
void solve(){
	scanf("%d%d",&n,&mod);
	if(!n) puts("0");
	else if(qpow(n,(mod-1)/2)==mod-1) puts("Hola!");
	else{
		while(1){
			int x=rng60()%mod;w=(1ll*x*x-n+mod)%mod;
			if(qpow(w,(mod-1)/2)==mod-1){
				int pw=(mod+1)/2;
				comp mul(1,0),v(x,1);
				for(;pw;pw>>=1,v=v*v) if(pw&1) mul=mul*v;
				if(mul.x<mod-mul.x) printf("%d %d\n",mul.x,mod-mul.x);
				else printf("%d %d\n",mod-mul.x,mul.x);
				break;
			}
		}
	}
}

例题:

暂时咕着了。。。

欧拉函数与欧拉定理

欧拉函数

定义 \(\varphi(n)\) 为满足 \(a\in[1,n]\)\((a,n)=1\)\(a\) 的个数。特别地,\(\varphi(1)=1\)

譬如当 \(n=12\) 时,\(1\sim 12\) 中有 \(1,5,7,11\) 四个数与 \(12\) 互质,故 \(\varphi(12)=4\)

积性函数

简单讲一下什么是积性函数。

一个函数 \(f:\mathbb{N}*\to\mathbb{N}*\) 被称为积性函数,当且仅当 \(\forall (x,y)=1,f(xy)=f(x)f(y)\)

这个函数又被称为完全积性函数,如果 \(\forall x,y\in\mathbb{N}*,f(xy)=f(x)f(y)\),也就是少了 \((x,y)=1\) 这个条件上式依然成立。

显然完全积性函数 \(\in\) 积性函数。

欧拉函数的性质

下面列出了欧拉函数的几个性质:

  1. \(p\) 为质数,则 \(\varphi(p)=p-1\)

    证明:由于 \(p\) 为质数,则显然 \([1,p-1]\) 中的所有数都与 \(p\) 互质,故 \(\varphi(p)=p-1\)

  2. \(p\) 为质数,\(k\in\mathbb{N}*\),则 \(\varphi(p^k)=(p-1)\times p^k\)

    证明:显然,与 \(p^k\) 不互质的数都是 \(p\) 的倍数,而 \([1,p^k]\) 中共有 \(p^{k-1}\)\(p\) 的倍数,故 \(\varphi(p^k)=(p-1)\times p^{k-1}\)

  3. \(n\) 的质因数分解形式为 \(n=p_1^{k_1}·p_2^{k_2}\dots p_m^{k_m}\),则 \(\varphi(n)=n\times\prod\limits_{i=1}^m\dfrac{p_i-1}{p_i}\)

    证明:首先有一个很显然的结论,那就是如果一个数 \(m\)\(n\),那么 \(m\) 至少与 \(n\) 有一个公共的质因子。我们考虑用一个“筛”的思想将 \(1\sim n\) 中所有与 \(n\) 互质的数一一筛去。我们先将 \([1,n]\) 中所有数标记为“与 \(n\) 互质”,先考虑 \(p_1\),显然 \(1\sim n\) 中有 \(\dfrac{n}{p_1}\) 个数与 \(n\) 有公共的质因子 \(p_1\),将这些数全部筛去,还剩 \(n\times\dfrac{p_1-1}{p_1}\) 个数,再考虑 \(p_2\),由于 \((p_1,p_2)=1\),故剩余的数中模 \(p_2\)\(0,1,2,\dots,p_2-1\) 的数的个数都是相等的,筛去了 \(n\times\dfrac{p_1-1}{p_1}\times\dfrac{1}{p_2}\) 个数,还剩 \(n\times\dfrac{p_1-1}{p_1}\times\dfrac{p_2-1}{p_2}\) 个数,接下来考虑 \(p_3,p_4,\dots\),最后还剩 \(n\times\prod\limits_{i=1}^m\dfrac{p_i-1}{p_i}\) 个数。显然与 \(n\) 互质的数永远不会被筛去,与 \(n\) 不互质的某个数 \(m\),假设它与 \(n\)\(k\) 个公共质因子 \(p_{i_1},p_{i_2},\dots,p_{i_k}\),其中 \(i_1<i_2<\dots<i_k\),那么它恰好会在 \(p_{i_1}\) 处筛去一次,故剩余的数包含且恰好包含了 \([1,n]\) 中所有与 \(n\) 互质的数,于是有 \(\varphi(n)=n\times\prod\limits_{i=1}^m\dfrac{p_i-1}{p_i}\)

  4. \(\varphi(n)\) 为积性函数但不是完全积性函数,即 \(\forall (x,y)=1,\varphi(xy)=\varphi(x)\varphi(y)\)

    假设 \(x\) 的质因数为 \(p_1,p_2,\dots,p_{\alpha}\),\(y\) 的质因数为 \(q_1,q_2,\dots,q_{\beta}\),由于 \((x,y)=1\)\(p_i\neq q_j\),故 \(xy\) 中恰好包含了 \(p_1,p_2,\dots,p_{\alpha},q_1,q_2,\dots,q_{\beta}\)\(\alpha+\beta\) 个质因数,于是 \(\varphi(xy)=xy\times\prod\limits_{i=1}^{\alpha}\dfrac{p_i-1}{p_i}\times\prod\limits_{i=1}^{\beta}\dfrac{q_i-1}{q_i}=(x\times\prod\limits_{i=1}^{\alpha}\dfrac{p_i-1}{p_i})\times(y\times\prod\limits_{i=1}^{\beta}\dfrac{q_i-1}{q_i})=\varphi(x)\varphi(y)\)

    \(\varphi(4)=2,\varphi(6)=2,\varphi(24)=8\neq \varphi(4)\times\varphi(6)\),故 \(\varphi(n)\) 为积性函数但不是完全积性函数。

  5. 对于 \(x,y\in\mathbb{N}*\),若 \(x\mid y\)\(\varphi(xy)=x\varphi(y)\)

    证明:和上一个定理证明方法类似,假设 \(x\) 包含的质因子集合 \(S=\{p_1,p_2,\dots,p_{\alpha}\}\)\(y\) 包含的质因子集合为\(T=\{q_1,q_2,\dots,q_{\beta}\}\),由于 \(x\mid y\),必然有 \(S\subseteq T\),于是 \(xy\) 包含的质因子集合也为 \(T\),即 \(\varphi(xy)=xy\times\prod\limits_{i=1}^{\beta}\dfrac{q_i-1}{q_i}=x\times(y\times\prod\limits_{i=1}^{\beta}\dfrac{q_i-1}{q_i})=x\varphi(y)\)

  6. \(\forall n>2,\varphi(n)\) 为偶数

    证明:对于 \(m\leq n\)\((m,n)=1\),必有 \((n-m,n)=1\),否则假设 \(n=ak,n-m=bk(k>1)\),则 \(m=(a-b)k\)\((m,n)=k>1\),矛盾!而对于奇数 \(n\),不存在整数 \(m\) 使得 \(n-m=m\),对于 \(n>2\) 的偶数,虽然 \(n-\dfrac{n}{2}=\dfrac{n}{2}\),但 \((\dfrac{n}{2},n)>1\)。故所有 \(\leq n\)\(n\) 互质的数都可以两两配对,原命题成立。

  7. \(\color{Red}{\sum\limits_{d\in[1,n],d|n}\varphi(d)=n}\)(very important!)

    证明:考虑 \(1\sim n\) 中的某个数 \(x\),设 \(d=\gcd(n,x),n=n'd,x=x'd\),那么显然有 \((n',x')=1,d|n,x'\leq n'\)。我们设 \(S_d=\{x|x\in [1,n],\dfrac{n}{\gcd(n,x)}=d\}\),那么显然 \(x'\) 满足 \(x'\leq d\)\((x',d)=1\),并且对于所有 \(\gcd(x',d)=1\)\(x'\) 都有 \(x'·\dfrac{n}{d}\in S_d\),故 \(|S_d|=\varphi(d)\),而对于 \(d\nmid n\)\(S_d=\varnothing\),也就是说对于任意 \(x\in [1,n]\) 都存在恰好一个 \(d|n\) 使得 \(x\in S_d\),故 \(\sum\limits_{d|n}|S_d|=n\),即 \(\sum\limits_{d\in[1,n],d|n}\varphi(d)=n\)

求欧拉函数的方法

一种求欧拉函数的方法是直接 \(\mathcal O(\sqrt{n})\) 地枚举 \(n\) 的质因子并用 \(\varphi(n)=n\times\prod\limits_{i=1}^m\dfrac{p_i-1}{p_i}\) 直接计算,一般用于处理 \(10^9\) 级别的数据。

int phi(int x){
	int tmp=x,ret=x;
	for(int i=2;i*i<=x;i++) if(tmp%i==0){
		ret=ret/i*(i-1);
		while(tmp%i==0) tmp/=i;
	} if(tmp>1) ret=ret/tmp*(tmp-1);
	return ret;
}

还有一种方法是用线性筛的方法在线性时间内求出某个数之内所有数的欧拉函数,大体框架和和线性筛类似,一般在值域较小时用于预处理,具体见代码吧:

bitset<MAXV+5> vis;
int pr[MAXV/10+5],prcnt=0,phi[MAXV+5];
void sieve(int n){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){pr[++prcnt]=i;phi[i]=i-1;}//性质 1:对于质数 p,phi[p]=p-1
		for(int j=1;j<=prcnt&&pr[j]*i<=n;j++){
			vis[pr[j]*i]=1;
			if(i%pr[j]==0){phi[pr[j]*i]=phi[i]*pr[j];break;}//性质 5:对于 x|y,phi(xy)=xphi(y)
			else phi[pr[j]*i]=phi[pr[j]]*phi[i];//性质 4:对于 (x,y)=1,phi(xy)=phi(x)phi(y)
		}
	}
}

最后说句闲话,\(n\) 以内质数个数大约是 \(\dfrac{n}{\ln n}\) 级别的,具体为什么我不太清楚,反正就当个结论记着罢。

欧拉定理

真·欧拉 nb,今天上午 XES 学了个公式叫 \(v-e+f=2\) 也叫欧拉定理来着的?

(数论中的)欧拉定理说的是这样一件事:对于 \((a,m)=1\)\(a^{\varphi(m)}\equiv 1\pmod{m}\)

\(m\) 为质数时有 \(a^{m-1}\equiv 1\pmod{m}\),此时该定理又被称为“费马小定理”。

证明:将 \([1,m]\) 中与 \(m\) 互质的数记作集合 \(S\),再记集合 \(T=\{ax\bmod m|x\in S\}\)

先证明两个 Lemma。

Lemma 1:\(T\) 中不存在相同的数,因为假设 \(\exist x,y\in S\) 使得 \(ax\equiv ay\pmod{m}\),那么就有 \(a(x-y)\equiv 0\pmod{m}\)。而 \((a,m)=1\),故 \(x\equiv y\pmod{m}\)。又 \(x,y\in [1,m],x\neq y\),故 \(x,y\)\(m\) 不同余,矛盾!

Lemma 2:\(\forall x\in T,(x,m)=1\)。因为对于 \(x\in S\),由已知 \((a,m)=1,(x,m)=1\),故 \(a,x\)\(m\) 不含公共质因子,于是 \((ax,m)=1\),得证。

由两个引理可知 \(|T|=|S|=\varphi(m)\),且 \(T\) 中的数均与 \(m\) 互质。而 \([1,m]\) 中与 \(m\) 互质的数有且仅有 \(\varphi(m)\) 个,故 \(S,T\) 组成完全相同。于是我们有 \(\prod\limits_{(x,m)=1}x\equiv\prod\limits_{(x,m)=1}ax\pmod{m}\),记 \(P=\prod\limits_{(x,m)=1}x\bmod m\),则 \(P\equiv a^{\varphi(m)}P\pmod{m}\),显然 \(P\neq 0\),故 \(a^{\varphi(p)}\equiv 1\pmod{p}\)。得证。

注:这边有的人会进入一个误区,那就是有人认为循环节长度就是 \(\varphi(m)\),i.e.,最小的满足 \(a^x\equiv 1\pmod{m},x>0\)\(x\) 就是 \(\varphi(m)\),这个理解是错误的。我们就拿 \(a=2,m=7\) 举例,\(2\) 的幂模 \(7\) 的余数分别为 \(1,2,4,1,2,4\dots\),我们发现循环节长度为 \(3\neq 6=\varphi(m)\)。实际上这里有一个定理,那就是这样的 \(x\) 必定是 \(\varphi(m)\) 的约数,证明就考虑反证法,假设 \(x\nmid\varphi(m)\),那么显然 \(\exist r,rx<\varphi(m)<(r+1)x\),这样就有 \(a^{rx}=(a^x)^r\equiv 1\pmod{m}\),而由欧拉定理 \(a^{\varphi(m)}\equiv 1\pmod{m}\),故 \(a^{\varphi(m)-rx}\equiv 1\pmod{m}\),而根据 \(rx<\varphi(m)<(r+1)x\)\(\varphi(m)-rx<x\),也就是说我们找到了更小的满足 \(a^x\equiv 1\pmod{m}\)\(x\),矛盾!

扩展欧拉定理

yet another 扩展xxx……

欧拉定理还能扩展到不互质的情况,具体来说:

\[a^x\bmod m=\begin{cases}a^{x\bmod\varphi(m)}&(a,x)=1\\a^x&x\leq\varphi(m)\\a^{x\bmod\varphi(m)+\varphi(m)}&x>\varphi(m)\end{cases} \]

说白了就是前 \(\varphi(m)\) 个还不一定进入循环节,后面每 \(\varphi(m)\) 个一循环(注意:这边的 \(\varphi(m)\) 也未必是循环节长度)。

举个例子就明白了,考察 \(14\) 的幂模 \(44\) 的值:\(1,14,20,4,16,36,20,4,16,36,\dots\)

不难发现,前面有几个未进入循环节,后面就每 \(4\) 个一循环了。

证明:考虑设 \(a=p_1^{k_1}·p_2^{k_2}·p_3^{k_3}\dots p_t^{k_t}\),我们只需对每个 \(p_i\) 证出 \((p_i^{k_i})^x\equiv (p_i^{k_i})^{x\bmod\varphi(m)+\varphi(m)}\pmod{p_i^{k_i}}\),后面的部分可用 CRT 说明。

考虑某个质因子 \(p\),设 \(m=s·p^k\)\((s,p)=1\)。根据欧拉定理有 \(p^{\varphi(s)}\equiv 1\pmod{s}\)。而根据 \((s,p^k)=1\) 可知 \(\varphi(m)=\varphi(s)\varphi(p^k)\),故 \(\varphi(s)\mid\varphi(m)\)。故 \(p^{\varphi(m)}\equiv 1\pmod{s}\)。根据同余的性质,同余号左右两边同乘 \(p^k\) 可得 \(p^{\varphi(m)+k}\equiv p^k\pmod{s·p^k}\)。而 \(s·p^k=m\),故 \(p^{\varphi(m)+k}\equiv p^k\pmod{m}\)。考虑某个 \(c\geq k\),显然有 \(p^c=p^{c-k+k}=p^{c-k}·p^k\equiv p^{c-k}·p^{k+\varphi(m)}=p^{c+\varphi(m)}\)。于是我们得到了公式 \(\forall c\geq k,p^c\equiv p^{c+\varphi(m)}\pmod{m}\)。而显然 \(k\leq\varphi(m)\)。故 \(p^x\equiv p^{x\bmod\varphi(m)+\varphi(m)}\)。两边同时 \(k\) 次方可得 \((p^k)^{x}\equiv (p^k)^{x\bmod\varphi(m)+k\varphi(m)}\pmod{p}\),得证。

原根与阶

定义 \(a\) 在模 \(m\) 意义下的阶为满足 \(a^x\equiv 1\pmod{m}\) 的最小整数 \(x\),记作 \(\text{ord}_ma\),有的地方也会记作 \(\delta_ma\)。显然 \(a\) 在模 \(m\) 意义下的阶存在的充要条件为 \((a,m)=1\),这个在 BSGS 的地方就证过了。

有关阶的一个很重要的结论是 \(a^x\equiv 1\pmod{m}\Leftrightarrow\text{ord}_ma\mid x\)

后者推前者是相当容易的,这里就不再赘述了。前者推后者事实上我们在欧拉定理的部分已经证过了,这里再重复一遍,假设 \(\text{ord}_ma\nmid x\),那么显然 \(\exist r,r\text{ord}_ma<x<(r+1)\text{ord}_ma\),这样就有 \(a^{r\text{ord}_ma}=(a^{\text{ord}_ma})^r\equiv 1\pmod{m}\),而 \(a^x\equiv 1\pmod{m}\),故 \(a^{x-r\text{ord}_ma}\equiv 1\pmod{m}\),而根据 \(r\text{ord}_ma<x<(r+1)\text{ord}_ma\)\(x-r\text{ord}_ma<\text{ord}_ma\),也就是说我们找到了更小的满足 \(a^x\equiv 1\pmod{m}\)\(x\),与阶的定义矛盾!

原根

定义一个数 \(g\) 为模 \(m\) 意义下的原根,当且仅当 \(\text{ord}_gm=\varphi(m)\)

它还有一个等价的定义,那就是 \(g^1,g^2,g^3,\cdots,g^{\varphi(m)}\) 两两模 \(m\) 不同余。

证明:充分性:由于 \(g^1,g^2,g^3,\cdots,g^{\varphi(m)}\) 两两模 \(m\) 不同余,必然有 \(\forall x\in[1,\varphi(m)),g^x\not\equiv g^{\varphi(m)}=1\),由阶的定义可知 \(\text{ord}_gm=\varphi(m)\)。必要性:反证法,假设 \(\exist x,y\in[1,\varphi(m)],x<y,g^x\equiv g^y\pmod{m}\),由 \(g\) 在模 \(m\) 意义下的阶存在可知 \((g,m)=1\),故 \((g^x,m)=1\),在同余等式 \(g^x\equiv g^y\pmod{m}\) 两边同乘 \(g^{-x}\) 可得 \(g^{y-x}\equiv 1\pmod{m}\),而由 \(x,y\in [1,\varphi(m)]\)\(y-x<\varphi(m)\),与阶的定义矛盾!故假设不成立,原命题成立。

原根的存在性

并不是所有的模数 \(m\) 都存在原根,事实上只有 \(2,4\) 及形如 \(p^k,2p^k\) 的数才存在原根(其中 \(p\) 为奇质数,\(k\in\mathbb{N}^+\)),至于为什么我也不太清楚,反正就当个定理用着就行了。

原根的判定

对于某数 \(a\),如果它为模 \(m\) 意义下的原根,那么首先必须有 \((a,m)=1\),否则就没什么阶可谈了,就更不用说原根了。

其次根据阶的定理,\(\forall (x,m)=1,\text{ord}_mx\mid\varphi(m)\),所以如果 \(a\) 不是模 \(m\) 意义下的原根,那么必然有 \(\text{ord}_ma\)\(\varphi(m)\) 的真因子,故我们枚举 \(\varphi(m)\) 真因子 \(p\),如果 \(\exist a^p\equiv 1\pmod{m}\) 那么意味着 \(a\) 不是模 \(m\) 意义下的原根,否则 \(a\) 为模 \(m\) 意义下的原根。

这里有一个小小的优化,那就是只用枚举 \(\varphi(m)\) 的所有质因子 \(p\) 并检验 \(a^{\varphi(m)/p}\equiv 1\pmod{m}\) 即可,正确性显然。

求一个数全部原根的做法

首先我们找出 \(m\) 的最小原根 \(g\),这里再一次不加证明地抛出一个定理:一个数最小原根的大小是 \(\sqrt[4]{m}\) 级别的,故暴力循环 \(+\) 按照上面所说的方式判定原根的复杂度是 ok 的,至于为什么我也不知道,btw 这种事情你管这么多干嘛呢,就当个定理记在脑子里罢/wq

下面要证明的一件事是:\(m\) 的原根个数为 \(\varphi(\varphi(m))\),并且都可以表示为 \(g^k\bmod m,k\in[1,\varphi(m)],(k,\varphi(m))=1\) 的形式。

证明:首先很明显的一点是 \(g^1,g^2,\dots,g^{\varphi(m)}\) 两两模 \(m\) 不同余,故这 \(\varphi(\varphi(m))\) 个数两两互不相同。

其次,我们先证明一个引理,\(a^x\equiv a^y\pmod{m}\Leftrightarrow x\equiv y\pmod{\text{ord}_ma}\)。充分性:不妨设 \(x<y\),因为 \(x\equiv y\pmod{\text{ord}_ma}\),必有 \(y-x=k\text{ord}_ma,k\in\mathbb{Z}\),故 \(a^{y-x}=a^{\text{ord}_mak}=(a^{\text{ord}_ma})^k\equiv 1\pmod{m}\),两边同乘 \(a^x\) 可得 \(a^x\equiv a^y\pmod{m}\)。必要性:由于 \(\text{ord}_ma\) 有意义,\((a,m)=1\),故 \((a^x,m)=1\),两边同乘 \(a^x\) 的逆元可得 \(1\equiv a^{y-x}\pmod{m}\),根据阶的定义知 \(\text{ord}_ma\mid y-x\),得证。

最后考虑怎样证明原命题。一方面,假设 \(\exist k\in[1,\varphi(m)],(k,\varphi(m))=1\) 且满足 \(\exist x,y\in [1,\varphi(m)],x\ne y\) 使得 \((g^{k})^x\equiv (g^{k})^y\pmod{m}\),那么根据引理得 \(kx\equiv ky\pmod{\text{ord}_mg}\),而由 \(g\)\(m\) 的原根知 \(\text{ord}_mg=\varphi(m)\),故 \(\varphi(m)\mid k(y-x)\),而 \((k,\varphi(m))=1\),故 \(\varphi(m)\mid y-x\),又 \(x,y\in [1,\varphi(m)],x\ne y\) 可推出矛盾,故所有可表示为 \(g^k\bmod m\) 的数,其中 \(k\in[1,\varphi(m)],(k,\varphi(m))=1\),均为 \(m\) 的原根。另一方面,\(\forall k'\in[1,\varphi(m)],(k',\varphi(m))>1\),设 \(d=(k',\varphi(m)),k'=k''d\),那么 \((g^{k'})^{\frac{\varphi(m)}{d}}=(g^{k''d})^{\frac{\varphi(m)}{d}}=(g^{\varphi(m)})^{k''}\equiv 1\pmod{m}\),故 \(g^{k'}\) 不是 \(m\) 的原根,得证。

例题:

咕咕咕咕咕咕咕咕咕咕咕咕,一排鸽子缓缓飞过:

🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊🕊

整除分块

一个很实用的 trick 哦

首先看一道例题:CF616E Sum of Remainders,题目要我们求 \(\sum\limits_{i=1}^mn\bmod i\)

老司机一看到 \(\bmod\) 就会将其替换为除法,即 \(i\bmod j=i-j\times\lfloor\dfrac{i}{j}\rfloor\)

于是原式可化为 \(\sum\limits_{i=1}^mn-i\times\lfloor\dfrac{n}{i}\rfloor=nm-\sum\limits_{i=1}^mi\times\lfloor\dfrac{n}{i}\rfloor\)

可是这东西暴力计算还是不行啊。。。

注意到本题数据范围 \(10^{13}\) 给得非常微妙,应该是放根号算法过去的,于是我们考虑根号分治。

回忆起小学奥数时学过的一个性质:当 \(i\) 很小的时候,\(\lfloor\dfrac{n}{i}\rfloor\) 差距很大,当 \(i\) 很大的时候,\(\lfloor\dfrac{n}{i}\rfloor\) 非常紧凑。

那么这个“很小”和“很大”的分界点究竟是什么呢?就是我们期待的 \(\sqrt{n}\) 了。

于是考虑一个暴力做法:对于 \(i\leq\sqrt{n}\) 暴力计算显然时间复杂度不会炸,对于 \(i>\sqrt{n}\) 枚举 \(\lfloor\dfrac{n}{i}\rfloor\) 的值,显然满足 \(\lfloor\dfrac{n}{i}\rfloor=x\)\(i\) 会构成一个区间 \([l,r]\)。由于这个区间中 \(\lfloor\dfrac{n}{i}\rfloor\) 的值相同,所以我们直接用 \(\lfloor\dfrac{n}{i}\rfloor\times\sum\limits_{j=l}^rj\) 就可以计算这一段的贡献了,后面那东西显然可以在常数时间内求出。

事实上我们并不用把这个“根号”体现在程序中,考虑把 \(\lfloor\dfrac{n}{i}\rfloor\) 的表列出来看看它长啥样,比方说 \(n=10\),那么 \(\lfloor\dfrac{n}{i}\rfloor\) 的值分别为 \(10,5,3,2,2,1,1,1,1,1\),我们发现这些数构成了一个个“块”,这也就是“整除分块”名字的由来。显然块的个数不会超过 \(2\sqrt{n}\),于是我们考虑改为枚举块。我们记录两个变量 \(l,r\) 表示当前块的左端点、右端点,这里有一个结论是对于左端点为 \(l\) 的块,它的右端点 \(r=\lfloor\dfrac{n}{\lfloor\dfrac{n}{l}\rfloor}\rfloor\)

简单证明一下:设 \(x\) 满足 \(\lfloor\dfrac{n}{x}\rfloor=\lfloor\dfrac{n}{l}\rfloor\),那么显然 \(\dfrac{n}{x}\geq\lfloor\dfrac{n}{l}\rfloor\),两边同时取倒数可得 \(\dfrac{x}{n}\le\dfrac{1}{\lfloor\dfrac{n}{l}\rfloor}\),两边再同乘 \(n\) 可得 \(x\le\dfrac{n}{\lfloor\dfrac{n}{l}\rfloor}\),也就是说 \(x>\dfrac{n}{\lfloor\dfrac{n}{l}\rfloor}\) 都不符合题意。至于充分性……假设 \(v=\lfloor\dfrac{n}{l}\rfloor\),设 \(n=pv+q(q<v)\),显然 \(q<l\),因为 \(n-vl<l\),而 \(p\ge l\),故 \(q=n-vp<l\leq p\),故 \(v=\lfloor\dfrac{n}{p}\rfloor\),即 \(\lfloor\dfrac{n}{\lfloor\dfrac{n}{\lfloor\dfrac{n}{l}\rfloor}\rfloor}\rfloor=\lfloor\dfrac{n}{l}\rfloor\),得证。

大体代码长这样:

for(ll l=1,r;l<=min(n,m);l=r+1){
    r=(n/(n/l));
    计算贡献
}

当然整除分块还有一些变种:

  1. \(\sum\limits_{i=1}^mf(i)\lfloor\dfrac{n}{i}\rfloor\):类似于上面的情形,枚举 \(\lfloor\dfrac{n}{i}\rfloor\) 所在的块,然后求出 \(f(i)\) 的前缀和来计算贡献。
  2. \(\sum\limits_{i=1}^x\sum\limits_{j=1}^y\lfloor\dfrac{n}{i}\rfloor\lfloor\dfrac{m}{i}\rfloor\):也是加个小小的改动,将 \(r\) 的值设为 \(r=\min(\lfloor\dfrac{n}{\lfloor\dfrac{n}{l}\rfloor}\rfloor,\lfloor\dfrac{m}{\lfloor\dfrac{m}{l}\rfloor}\rfloor)\),这样能保证 \([l,r]\) 中所有数 \(\lfloor\dfrac{n}{i}\rfloor,\lfloor\dfrac{m}{i}\rfloor\) 值都是相同的,并且块的个数还是根号级别的。

例题:

咕咕咕

posted @ 2021-02-10 23:20  tzc_wk  阅读(330)  评论(8编辑  收藏  举报