数学杂记

记录一些琐碎的数学知识(也可能不是数学)。以下内容重点放在记结论,以便作者复习。慢慢补充吧,东西会比较杂。。

最大公约数

由公约数的基本性质可得:

inline int gcd(int a,int b){return b?gcd(b,a%b):a;}

扩展欧几里得

求解关于 x , y x,y x,y的二元一次方程: a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
当等式右端不是 g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数时,方程无解。
考虑求解: b x 1 + ( a % b ) y 1 = g c d ( b , a % b ) = g c d ( a , b ) bx_1+(a\%b)y_1=gcd(b,a\%b)=gcd(a,b) bx1+(a%b)y1=gcd(b,a%b)=gcd(a,b)
假设已经求出了 x 1 , y 1 x_1,y_1 x1,y1。转化:
b x 1 + ( a − ⌊ a b ⌋ ∗ b ) y 1 = g c d ( a , b ) bx_1+(a-\lfloor \frac{a}{b} \rfloor *b)y_1=gcd(a,b) bx1+(abab)y1=gcd(a,b)
a ∗ y 1 + b ∗ ( x 1 − ⌊ a b ⌋ ∗ y 1 ) = g c d ( a , b ) a*y_1+b*(x_1-\lfloor \frac{a}{b} \rfloor*y_1)=gcd(a,b) ay1+b(x1bay1)=gcd(a,b)
于是有: x = y 1 , y = x 1 − ⌊ a b ⌋ ∗ y 1 x=y_1,y=x_1-\lfloor \frac{a}{b} \rfloor*y_1 x=y1,y=x1bay1
当递归到最后一层,有: a = g c d ( a , b ) , b = 0 a=gcd(a,b),b=0 a=gcd(a,b),b=0,于是此时 x = 1 , y = 0 x=1,y=0 x=1,y=0
注意一下代码中 x x x y y y的螺旋走位。

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

中国剩余定理

求解一组线性同余方程,其中满足模数两两互质。
其实就是对于每一组考虑消去其它方程的影响。
{ x ≡ a 1    ( m o d   m 1 ) x ≡ a 2    ( m o d   m 2 )          ⋮ x ≡ a n    ( m o d   m n ) \begin{cases} x\equiv a_1\ \ (mod \ m_1) \\ x\equiv a_2\ \ (mod \ m_2) \\ \;\;\;\; \vdots \\ x\equiv a_n\ \ (mod \ m_n) \end{cases} xa1  (mod m1)xa2  (mod m2)xan  (mod mn)
M = ∏ m i M=\prod m_i M=mi T i = M m i T_i=\frac{M}{m_i} Ti=miM,考虑求解 r i r_i ri满足:
T i ∗ r i ≡ 1        ( m o d   m i ) ⟺ a i ∗ T i ∗ r i ≡ a i        ( m o d   m i ) T_i*r_i\equiv 1\;\;\;(mod \ m_i) \Longleftrightarrow a_i*T_i*r_i\equiv a_i\;\;\;(mod \ m_i) Tiri1(mod mi)aiTiriai(mod mi)
而同时,这里有 a i ∗ T i ∗ r i ≡ 0     ( m o d   m k ) , k ≠ i , k ∈ [ 1 , n ] a_i*T_i*r_i\equiv 0\ \ \ (mod\ m_k),k \not=i,k \in[1,n] aiTiri0   (mod mk),k=i,k[1,n]
于是 x x x有解: x 0 = ∑ i = 1 n a i ∗ T i ∗ r i x_0=\sum_{i=1}^{n} a_i*T_i*r_i x0=i=1naiTiri,通解有 x = x 0 + k ∗ M , k ∈ Z x=x_0+k*M,k\in \Z x=x0+kM,kZ
模板,比较坑,要龟速乘。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=15;
int k,a[N],b[N],x,y,mul=1,ans=0;
inline void turn(int &x,int mod){x=(x%mod+mod)%mod;}
inline void exgcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return;}
	exgcd(b,a%b,y,x),y-=a/b*x;
}
inline int Mul(int a,int b,int ret=0){
	for(;b;b>>=1,a=(a+a)%mul)
		if(b&1) (ret+=a)%=mul;
	return ret;
}
signed main(){
	scanf("%lld",&k);
	for(int i=1;i<=k;++i) scanf("%lld",a+i);
	for(int i=1;i<=k;++i) scanf("%lld",b+i),mul*=b[i];
	for(int i=1;i<=k;++i){
		int tmp=mul/b[i];
		exgcd(tmp,b[i],x,y),turn(x,b[i]),turn(a[i],b[i]);
		ans+=Mul(Mul(a[i],tmp),x),turn(ans,mul);
	}cout<<ans<<'\n';
}

扩展中国剩余定理

同上,但不满足模数两两互质。此时 T i ∗ r i ≡ 1    ( m o d   m i ) T_i*r_i\equiv 1\;(mod \ m_i) Tiri1(mod mi)可能会无解,因为没有互质的条件。
考虑两两合并:
{ x ≡ a 1    ( m o d   m 1 ) x ≡ a 2    ( m o d   m 2 ) ⟺ { x = a 1 + p ∗ m 1 x = a 2 + q ∗ m 2 \begin{cases} x\equiv a_1\ \ (mod \ m_1)\\ x\equiv a_2\ \ (mod \ m_2) \end{cases} \Longleftrightarrow \begin{cases} x= a_1+p*m_1\\ x= a_2+q*m_2 \end{cases} {xa1  (mod m1)xa2  (mod m2){x=a1+pm1x=a2+qm2
将右侧两式相减得到一个二元一次方程组的形式:
p ∗ m 1 − q ∗ m 2 = a 2 − a 1       ① p*m_1-q*m_2=a_2-a_1 \ \ \ \ \ ① pm1qm2=a2a1     
x = p a 2 − a 1 g c d ( m 1 , m 2 ) , y = − q a 2 − a 1 g c d ( m 1 , m 2 ) x=\frac{p}{\frac{a_2-a_1}{gcd(m_1,m_2)}},y=\frac{-q}{\frac{a_2-a_1}{gcd(m_1,m_2)}} x=gcd(m1,m2)a2a1p,y=gcd(m1,m2)a2a1q,考虑求解:
x ∗ m 1 + y ∗ m 2 = g c d ( m 1 , m 2 )       ② x*m_1+y*m_2=gcd(m_1,m_2) \ \ \ \ \ ② xm1+ym2=gcd(m1,m2)     
首先,如果 g c d ( m 1 , m 2 ) ∤ a 2 − a 1 gcd(m_1,m_2) \not| a_2-a_1 gcd(m1,m2)a2a1,显然①式是无整数解的。否则一定有解。
利用 e x g c d exgcd exgcd把②式求解出来之后,得到 x , y x,y x,y,然后 x x x y y y分别乘上 a 2 − a 1 g c d ( m 1 , m 2 ) \frac{a_2-a_1}{gcd(m_1,m_2)} gcd(m1,m2)a2a1得到 p , − q p,-q p,q,随便取 p p p − q -q q代入上面大括号右侧式子( p p p − q -q q代出来是一样的)得到一个满足上述同余式的 x 0 x_0 x0。于是有:
{ x ≡ a 1 ≡ x 0    ( m o d   m 1 ) x ≡ a 2 ≡ x 0    ( m o d   m 2 ) \begin{cases} x\equiv a_1 \equiv x_0\ \ (mod \ m_1)\\ x\equiv a_2 \equiv x_0\ \ (mod \ m_2) \end{cases} {xa1x0  (mod m1)xa2x0  (mod m2)
接下来证明:
对于两个非零整数 a , b a,b a,b,且有整数 x , y x,y x,y,满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)(这是一定存在的):如果 a ∣ n , b ∣ n a|n,b|n an,bn,则 l c m ( a , b ) ∣ n lcm(a,b)|n lcm(a,b)n
a ′ = a g c d ( a , b ) , b ′ = b g c d ( a , b ) a'=\frac{a}{gcd(a,b)},b'=\frac{b}{gcd(a,b)} a=gcd(a,b)a,b=gcd(a,b)b,那么有:
n = n ( a x + b y ) g c d ( a , b ) = n a ′ x + n b ′ y n=\frac{n(ax+by)}{gcd(a,b)}=na'x+nb'y n=gcd(a,b)n(ax+by)=nax+nby
又有
a ∣ n , b ∣ n ⟹ a b ′ ∣ n b ′ , a ′ b ∣ n a ′ ⟹ a b ′ ∣ n b ′ y , a ′ b ∣ n a ′ x ⟹ l c m ( a , b ) ∣ n a ′ x + n b ′ y a|n,b|n \Longrightarrow ab'|nb',a'b|na' \Longrightarrow ab'|nb'y,a'b|na'x \Longrightarrow lcm(a,b)|na'x+nb'y an,bnabnb,abnaabnby,abnaxlcm(a,b)nax+nby
即:
l c m ( a , b ) ∣ n lcm(a,b)|n lcm(a,b)n

上面有:
m 1 ∣ x − x 0 , m 2 ∣ x − x 0 ⟹ l c m ( m 1 , m 2 ) ∣ x − x 0 m_1|x-x_0,m_2|x-x_0 \Longrightarrow lcm(m_1,m_2)|x-x_0 m1xx0,m2xx0lcm(m1,m2)xx0
即:
x − x 0 ≡ 0    ( m o d   l c m ( m 1 , m 2 ) ) ⟹ x ≡ x 0   ( m o d   l c m ( m 1 , m 2 ) ) x-x_0\equiv 0\ \ (mod \ lcm(m_1,m_2)) \Longrightarrow x \equiv x_0\ (mod \ lcm(m_1,m_2)) xx00  (mod lcm(m1,m2))xx0 (mod lcm(m1,m2))

于是这样一个一个合并即可。
模板,注意代码实现里,①式是先把 m 1 m_1 m1 m 2 m_2 m2 a 2 − a 1 a_2-a_1 a2a1 g c d ( m 1 , m 2 ) gcd(m_1,m_2) gcd(m1,m2)除掉。后面把 p p p代入 x x x的方程时,再把 m 1 m_1 m1 g c d ( m 1 , m 2 ) gcd(m_1,m_2) gcd(m1,m2)乘回去。不然要 W A WA WA,可能是爆 l o n g l o n g longlong longlong。还有无解的时候不能直接 b r e a k break break掉,因为还要读入。。

#include<cstdio>
#define int long long
#define re register
using namespace std;
inline int gcd(int a,int b){return (b)?gcd(b,a%b):a;}
//ax+by=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,y,x),y-=a/b*x;
}
int n,m1,a1,m2,a2,p,q;
signed main(){
	while(~scanf("%lld",&n)){
		scanf("%lld%lld",&m1,&a1);
		bool flag=1;
		for(int re i=2;i<=n;++i){
			scanf("%lld%lld",&m2,&a2);
			int g=gcd(m1,m2),lcm=m1*m2/g,A=a2-a1;
			if(A%g!=0){flag=0;continue;}
			m1/=g,m2/=g,A/=g,exgcd(m1,m2,p,q),p=(p*A%m2+m2)%m2;
			a1=(a1+p*m1*g)%lcm,m1=lcm;
		}
		if(!flag) puts("-1");
		else printf("%lld\n",a1);
	}
}

高斯消元

解决 n n n元一次方程组。复杂度 O ( n 3 ) O(n^3) O(n3)
只要记住一个一个地消元即可,红色是用来消元的位置。
红色下方消为0,消完之后往上求解即可。
下图为用第 i i i行第 i i i个消元。第 j j j行的每个系数整体要减去第 i i i行的每个系数乘以 a [ j ] [ i ] a [ i ] [ i ] \frac{a[j][i]}{a[i][i]} a[i][i]a[j][i],然而 a [ i ] [ i ] = 0 a[i][i]=0 a[i][i]=0怎么办?换成一个第 i i i列非 0 0 0的行即可。
还有一点,就是取对应列最大的一行作为主元来消元可以减小精度误差,洛谷的题解里似乎有解释。
如果选出的主元等于0,说明它下面的系数都为0,在有解的情况下,主元可取任意值,它前面的元素随它的变化而变化,有无穷多解。相当于是少了一个方程。
若某行的系数均为 0 0 0而常数项非 0 0 0,则无解。下面代码只判了是否是唯一解。模板传送门
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=105;
const double eps=1e-8;
double a[N][N],ans[N];int n;
inline int sgn(double x){
	if(x>eps) return 1;
	if(x<-eps) return -1;
	return 0;
}
inline int Guass(){
	for(int i=1;i<=n;++i){
		int k=i;
		for(int j=i+1;j<=n;++j)
			if(fabs(a[k][i])<fabs(a[j][i])) k=j;
		swap(a[i],a[k]);
		if(!sgn(a[i][i])) return 0;
		for(int j=i+1;j<=n;++j)
			for(int k=i+1;k<=n+1;++k)
				a[j][k]-=a[j][i]/a[i][i]*a[i][k];
	}
	for(int i=n;i;--i){
		for(int j=i+1;j<=n;++j)
			a[i][n+1]-=ans[j]*a[i][j];
		ans[i]=a[i][n+1]/a[i][i];
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n+1;++j)
			scanf("%lf",&a[i][j]);
	if(!Guass()) return puts("No Solution"),0;
	for(int i=1;i<=n;++i) printf("%.2lf\n",ans[i]);
}

欧拉定理&广义欧拉定理

欧拉定理:若 a , m a,m a,m为正整数,且 g c d ( a , m ) = 1 gcd(a,m)=1 gcd(a,m)=1,那么有:
a φ ( m ) ≡ 1   ( m o d   m ) a^{\varphi(m)} \equiv 1 \ (mod \ m) aφ(m)1 (mod m)
广义欧拉定理:
a b ≡ { a b % φ ( m ) , g c d ( a , m ) = 1 a b , g c d ( a , m ) ≠ 1 , b < φ ( m ) a b % φ ( m ) + φ ( m ) , g c d ( a , m ) ≠ 1 , b ⩾ φ ( m ) a^b\equiv \begin{cases} a^{b\%\varphi(m)},gcd(a,m)=1\\ a^{b},gcd(a,m)\not=1,b<\varphi(m)\\ a^{b\%\varphi(m)+\varphi(m)},gcd(a,m)\not=1,b \geqslant \varphi(m) \end{cases} abab%φ(m),gcd(a,m)=1ab,gcd(a,m)=1,b<φ(m)ab%φ(m)+φ(m),gcd(a,m)=1,bφ(m)
在快速幂的时候要仔细想一想指数对不对,毕竟指数不能直接用 m m m取模。

原根

参考文章
参考《初等数论》 P 241 P241 P241
定义1 m ⩾ 1 , ( a , m ) = 1 m \geqslant 1,(a,m)=1 m1,(a,m)=1,使: a d ≡ 1   ( m o d   m ) a^d \equiv 1\ (mod\ m) ad1 (mod m)成立的最小正整数 d d d称为a对模m的指数(或阶),把它记做 δ m ( a ) \delta_m(a) δm(a).
定义2:当 δ m ( a ) = φ ( m ) \delta_m(a)=\varphi(m) δm(a)=φ(m)时,称 a a a是模 m m m的原根,简称m的原根

由欧拉定理: a φ ( m ) ≡ 1   ( m o d   m ) a^{\varphi(m)} \equiv 1 \ (mod \ m) aφ(m)1 (mod m),可知 δ m ( a ) ⩽ φ ( m ) \delta_m(a) \leqslant \varphi(m) δm(a)φ(m)
如何求质数的原根?
一般来说原根不会太大,暴力枚举 [ 2 , ⌊ x 4 ⌋ ] [2,\lfloor \sqrt[4] x \rfloor] [2,4x ]即可。
如何验证当前枚举的 a a a是不是原根?
首先,循环节长度 s s s一定满足 s ∣ φ ( m ) s|\varphi(m) sφ(m)
那么只需要找出 φ ( m ) \varphi(m) φ(m)的所有质因数 p 1 , p 2 , ⋯   , p k p_1,p_2,\cdots,p_k p1,p2,,pk
如果: ∀ p i , i ∈ [ 1 , k ] : a φ ( m ) p i ≢ 1   ( m o d   m ) \forall p_i,i\in[1,k]:a^{\frac{\varphi(m)}{p_i}} \not\equiv1\ (mod\ m) pi,i[1,k]:apiφ(m)1 (mod m)
a a a m m m的一个原根。附上模板

#include<bits/stdc++.h>
using namespace std;
int mod,tot=0,factor[31];
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
inline bool is_pri_root(int x){
	for(int i=1;i<=tot;++i) 
		if(quickpow(x,(mod-1)/factor[i])==1)
			return false;
	return true;
}
inline int find(int mod){
	int phi=mod-1;
	for(int i=2;i*i<=phi;++i)
		while(phi%i==0) factor[++tot]=i,phi/=i;
	if(phi!=1) factor[++tot]=phi;
	for(int i=1;;++i)
		if(is_pri_root(i)) return i;
}
int main(){
	scanf("%d",&mod),printf("%d\n",find(mod));
}

二项式反演

神犇666
f n = ∑ i = 0 n ( − 1 ) i ( n i ) g i ⟺ g n = ∑ i = 0 n ( − 1 ) i ( n i ) f i f_n=\sum_{i=0}^{n}(-1)^i \binom{n}{i}g_i \Longleftrightarrow g_n=\sum_{i=0}^{n}(-1)^i \binom{n}{i}f_i fn=i=0n(1)i(in)gign=i=0n(1)i(in)fi
这个式子有很强的对称性。一个更常用的结论:
f n = ∑ i = 0 n ( n i ) g i ⟺ g n = ∑ i = 0 n ( − 1 ) n − i ( n i ) f i f_n=\sum_{i=0}^{n} \binom{n}{i}g_i \Longleftrightarrow g_n=\sum_{i=0}^{n}(-1)^{n-i} \binom{n}{i}f_i fn=i=0n(in)gign=i=0n(1)ni(in)fi
可以用来解决 m i n _ m a x min\_max min_max容斥。

错排问题

例题
a a a数组为 1 1 1~ n n n的排列, ∀ a [ i ] ! = i \forall a[i]!=i a[i]!=i的排列方法有多少种?

D [ n ] D[n] D[n]为长度为 n n n的排列的错排方案数,有递推公式:
D [ n ] = ( n − 1 ) ∗ ( D [ n − 1 ] + D [ n − 2 ] ) D[n]=(n-1)*(D[n-1]+D[n-2]) D[n]=(n1)(D[n1]+D[n2])
证明:
考虑增量法求 D [ n ] D[n] D[n],假设已知 D [ 1 ] D[1] D[1]~ D [ n − 1 ] D[n-1] D[n1]
现在令所有元素有序排列好,即 a [ i ] = i a[i]=i a[i]=i
n n n个元素可以选择前 n − 1 n-1 n1个位置中的任意一个放进去,假设选了某个位置 k k k,那么这个位置的元素 k k k就被挤出来了。
如果 k k k放在了位置 n n n,现在就相当于是 n n n k k k交换了位置,剩下 n − 2 n-2 n2个元素需要错排。即为 D [ n − 2 ] D[n-2] D[n2]种方案。
如果 k k k不放在位置 n n n,相当于是把 a [ k ] ! = k a[k]!=k a[k]!=k的限制变为了 a [ n ] ! = k a[n]!=k a[n]!=k,由于 n n n的位置已经固定在 k k k,所以现在问题转化为了 1 1 1~ n − 1 n-1 n1的错排问题,方案数为 D [ n − 1 ] D[n-1] D[n1]。这 n − 1 n-1 n1个限制关系依然是一一对应的。

于是有: D [ n ] = ( n − 1 ) ∗ ( D [ n − 1 ] + D [ n − 2 ] ) D[n]=(n-1)*(D[n-1]+D[n-2]) D[n]=(n1)(D[n1]+D[n2])

初始状态 D [ 1 ] = 0 , D [ 2 ] = 1 D[1]=0,D[2]=1 D[1]=0,D[2]=1

二次剩余

以下船部内容参考:
《初等数论》第四章§5:模为素数的二次剩余

假定 p p p是奇素数,设 p ̸    ∣ a p \not\;\mid a pa,二次同余方程的一般形式是:
a x 2 + b x + c ≡ 0   ( m o d   p ) ⋯ ( 1 ) ax^2+bx+c \equiv 0\ (mod\ p) \cdots(1) ax2+bx+c0 (mod p)(1)
由于 p p p为奇素数, p ̸    ∣ a p \not\;\mid a pa,所以 p ̸    ∣ 4 a p \not\;\mid 4a p4a,所以 ( 1 ) (1) (1)式和同余方程:
4 a ( a x 2 + b x + c ) ≡ 0   ( m o d   p ) 4a(ax^2+bx+c) \equiv 0\ (mod\ p) 4a(ax2+bx+c)0 (mod p)
的解相同。上式可写为:
( 2 a x + b ) 2 ≡ b 2 − 4 a c   ( m o d   p ) (2ax+b)^2 \equiv b^2-4ac\ (mod\ p) (2ax+b)2b24ac (mod p)
y = 2 a x + b y=2ax+b y=2ax+b,于是有: y ≡ 2 a x + b   ( m o d   p ) y \equiv 2ax+b\ (mod\ p) y2ax+b (mod p),且:
y 2 ≡ b 2 − 4 a c   ( m o d   p ) y^2 \equiv b^2-4ac\ (mod\ p) y2b24ac (mod p)
显然 x x x y y y是一一对应的。于是问题转化为形如:
x 2 ≡ d   ( m o d   p ) x^2 \equiv d\ (mod\ p) x2d (mod p)
的同余方程,也就是求解 y y y。当 p ∣ d p \mid d pd,仅有一解: x ≡ 0   ( m o d   p ) x\equiv0\ (mod\ p) x0 (mod p)
所以,下面恒假定 p ̸    ∣ d p \not\;\mid d pd
定义1:设素数 p > 2 , d ∈ Z , p ̸    ∣ d p>2,d\in \Z,p \not\;\mid d p>2,dZ,pd,若 x 2 ≡ d   ( m o d   p ) x^2 \equiv d\ (mod\ p) x2d (mod p)有解,称d是模p的二次剩余,否则称d是模p的二次非剩余
定理1:在模 p p p的一个既约剩余系中,恰有 p − 1 2 \frac{p-1}{2} 2p1个模 p p p的二次剩余, p − 1 2 \frac{p-1}{2} 2p1个模 p p p的二次非剩余。若 d d d是模 p p p的二次剩余,则 x 2 ≡ d   ( m o d   p ) x^2 \equiv d\ (mod\ p) x2d (mod p)的解数为 2 2 2
证明略。
定理2(Euler判别法):设素数 p > 2 p>2 p>2 p ̸    ∣ d p \not\;\mid d pd,那么:
d d d是模 p p p的二次剩余的充分必要条件是:
d p − 1 2 ≡ 1   ( m o d   p ) ⋯ ( 3 ) d^{\frac{p-1}{2}}\equiv 1\ (mod\ p)\cdots(3) d2p11 (mod p)(3)
d d d是模 p p p的非二次剩余的充分必要条件是:
d p − 1 2 ≡ − 1   ( m o d   p ) ⋯ ( 4 ) d^{\frac{p-1}{2}}\equiv -1\ (mod\ p)\cdots(4) d2p11 (mod p)(4)

Wilson定理:设 p p p是素数, r 1 , ⋯   , r p − 1 r_1,\cdots,r_{p-1} r1,,rp1是模 p p p的既约剩余系,有:
r 1 ⋯ r p − 1 ≡ − 1 ( m o d   p ) r_1\cdots r_{p-1}\equiv -1(mod\ p) r1rp11(mod p)
特别地,有:
( p − 1 ) ! ≡   − 1 ( m o d   p ) (p-1)!\equiv\ -1(mod\ p) (p1)! 1(mod p)

下面证明 E u l e r Euler Euler判别法:
首先证明 ∀ d ∈ Z , p ̸    ∣ d \forall d\in \Z,p\not\;\mid d dZ,pd ( 3 ) (3) (3) ( 4 ) (4) (4)有且仅有一式成立(平方差):
d p − 1 ≡ 1 ( m o d   p ) ⇒ ( d p − 1 2 − 1 ) ( d p − 1 2 + 1 ) ≡ 0   ( m o d   p ) d^{p-1}\equiv 1(mod\ p) \Rightarrow (d^{\frac{p-1}{2}}-1)(d^{\frac{p-1}{2}}+1)\equiv 0 \ (mod\ p) dp11(mod p)(d2p11)(d2p1+1)0 (mod p)
所以不可能存在 ( 3 ) (3) (3) ( 4 ) (4) (4)都不成立的情况。
若两式都成立,则 p ∣ ( d p − 1 2 − 1 ) , p ∣ ( d p − 1 2 + 1 ) p \mid (d^{\frac{p-1}{2}}-1),p\mid (d^{\frac{p-1}{2}}+1) p(d2p11),p(d2p1+1)
⇒ p ∣ ( d p − 1 2 + 1 ) − ( d p − 1 2 − 1 ) ⇒ p ∣ 2 \Rightarrow p \mid (d^{\frac{p-1}{2}}+1)-(d^{\frac{p-1}{2}}-1)\Rightarrow p \mid 2 p(d2p1+1)(d2p11)p2
由于 p p p为奇素数,所以上述情况不可能成立,矛盾。
所以 ( 3 ) (3) (3) ( 4 ) (4) (4)有且仅有一式成立。
( 3 ) (3) (3)的必要性:若 d d d是模 p p p的二次剩余,则有 x 0 x_0 x0使得:
x 0 2 ≡ d ( m o d   p ) ⇒ x 0 p − 1 ≡ d p − 1 2 ( m o d   p ) ⇒ 1 ≡ d p − 1 2 ( m o d   p ) x_0^2\equiv d(mod\ p) \Rightarrow x_0^{p-1}\equiv d^{\frac{p-1}{2}}(mod\ p) \Rightarrow 1\equiv d^{\frac{p-1}{2}}(mod\ p) x02d(mod p)x0p1d2p1(mod p)1d2p1(mod p)

( 3 ) (3) (3)的充分性:若 ( 3 ) (3) (3)成立,则必有 p ̸    ∣ d p\not\;\mid d pd.考虑一次同余方程:
a x ≡ d ( m o d   p ) ax\equiv d(mod\ p) axd(mod p)
令模 p p p的既约剩余系为 S S S。那么对于 ∀ j ∈ S \forall j\in S jS,当 a = j a=j a=j,必有唯一的 x = x j ∈ S x=x_j\in S x=xjS使得方程成立。假设 d d d不是模 p p p的二次剩余:
那么必有 j ≠ x j j\not=x_j j=xj,否则若 j = x j j=x_j j=xj,有 j ∗ x j ≡ d ≡ x j 2 ( m o d   p ) j*x_j \equiv d \equiv x_j^2 (mod\ p) jxjdxj2(mod p),推出 d d d是模 p p p的二次剩余,矛盾。
现在把 S S S中的数按照 j , x j j,x_j j,xj两两配对,可以配出 p − 1 2 \frac{p-1}{2} 2p1组: j ∗ x j ≡ d ( m o d   p ) j*x_j \equiv d (mod\ p) jxjd(mod p)
于是有: ( p − 1 ) ! ≡ d p − 1 2 ( m o d   p ) (p-1)!\equiv d^{\frac{p-1}{2}} (mod\ p) (p1)!d2p1(mod p)
W i l s o n Wilson Wilson定理:
− 1 ≡ d p − 1 2 ( m o d   p ) -1\equiv d^{\frac{p-1}{2}}(mod\ p) 1d2p1(mod p)
与式 ( 3 ) (3) (3)矛盾。所以必有 j 0 j_0 j0使得 j 0 = x j 0 j_0=x_{j_0} j0=xj0,所以 d d d是模 p p p的二次剩余。这就证明了充分性。由已证部分可以立即推出剩下的结论。

Cipolla算法

求解关于x的同余方程:
x 2 ≡ n ( m o d   p ) x^2\equiv n(mod\ p) x2n(mod p)
p p p为奇素数。算法流程:
①首先找到 a a a使得 a 2 − n a^2-n a2n为模 p p p的二次非剩余。根据上面的定理1,在模 p p p的一个既约剩余系中,恰有 p − 1 2 \frac{p-1}{2} 2p1个模 p p p的二次剩余,所以如果随机取这个 a a a,找到满足条件的 a a a的期望次数为 2 2 2。根据 E u l e r Euler Euler判别法, ( a 2 − n ) p − 1 2 ≡ − 1 ( m o d   p ) {(a^2-n)}^{\frac{p-1}{2}}\equiv -1(mod\ p) (a2n)2p11(mod p)时满足条件。
②令 ω = a 2 − n \omega=\sqrt{a^2-n} ω=a2n ,求出 x 0 = ( a + ω ) p + 1 2 x_0=(a+\omega)^{\frac{p+1}{2}} x0=(a+ω)2p+1,答案有两个: x 1 = x 0 , x 2 = p − x 0 x1=x_0,x_2=p-x_0 x1=x0,x2=px0

几个需要特判的东西:
n = 0 n=0 n=0,则解为 x 1 = x 2 = 0 x_1=x_2=0 x1=x2=0
p = 2 p=2 p=2,则返回 n n n即可( n n n只有 0 , 1 0,1 0,1两种取值,两个解相同)

其他情况都有两个解。

具体证明参考

洛谷模板现在写代码越写越丑了。。

#include<bits/stdc++.h>
#define re register
#define cs const

namespace IO{
	cs int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
	template <typename T>
	inline T get(){
		char ch=gc();T x=0;
		while(!isdigit(ch)) ch=gc();
		while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
		return x;
	}
	inline int gi(){return get<int>();}
}
using IO::gi;

int T,n,mod,NQ;

inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}

struct plx{
	int x,y;
	plx(int X=0,int Y=0){x=X,y=Y;}
	friend inline plx operator*(cs plx &a,cs plx &b){
		return plx(add(mul(a.x,b.x),mul(mul(a.y,b.y),dec(mul(NQ,NQ),n))),add(mul(a.x,b.y),mul(a.y,b.x)));
	}
	friend inline plx operator^(plx a,int b){
		plx ret(1,0);
		for(;b;b>>=1,a=a*a) if(b&1)
			ret=ret*a;
		return ret;
	}
};

inline void solve(){
	n%=mod;
	if(!n){puts("0");return;}
	if(mod==2){printf("%d\n",n);return;}
	if(quickpow(n,(mod-1)>>1)==mod-1){puts("Hola!");return;}
	while(1){
		NQ=rand()%mod;
		if(quickpow(dec(mul(NQ,NQ),n),(mod-1)>>1)==mod-1)
			break;
	}
	int x0=(plx(NQ,1)^((mod+1)>>1)).x,x1=mod-x0;
	if(x0>x1) std::swap(x0,x1);
	printf("%d %d\n",x0,x1);
}

int main(){
//	freopen("5491.in","r",stdin);
	T=gi();
	while(T--) n=gi(),mod=gi(),solve();
}

积性函数的卷积

I ∗ μ = ϵ I*\mu=\epsilon Iμ=ϵ
μ ∗ i d = φ \mu * id=\varphi μid=φ
I ∗ i d = σ I*id=\sigma Iid=σ
I ∗ I = d I*I=d II=d
I ∗ φ = i d I*\varphi=id Iφ=id
注意 i d ( x ) = x , I ( x ) ≡ 1 id(x)=x,I(x) \equiv1 id(x)=x,I(x)1,不要搞混了T_T

1 1 1~ n n n中与 n n n互质的数的和:
∑ i = 1 n [ g c d ( n , i ) = = 1 ] ∗ i = n ∗ φ ( n ) + [ n = = 1 ] 2 \sum_{i=1}^{n} [gcd(n,i)==1]*i=\frac{n*\varphi(n)+[n==1]}{2} i=1n[gcd(n,i)==1]i=2nφ(n)+[n==1]
n = 1 n=1 n=1 n = 2 n=2 n=2时,上式和即为1.
n > 2 n>2 n>2时, φ ( n ) \varphi(n) φ(n)为偶数。如果 g c d ( n , a ) = 1 gcd(n,a)=1 gcd(n,a)=1,则 g c d ( n , n − a ) = 1 gcd(n,n-a)=1 gcd(n,na)=1
也就是说这些与 n n n互质的数两两配对凑出了 n n n,于是就有了上式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值