前置知识
初等数论,简单数学知识。
群论
很多数论知识都需要群论证明,我们先简单了解一下群论。
设 G G G 为一个非空集合,定义运算 ⋅ \cdot ⋅ ,( G , ⋅ ) (G,\cdot) ( G , ⋅ ) 为一个群当且仅当:
封闭性 :∀ a , b ∈ G , a ⋅ b ∈ G \forall a,b \in G,a \cdot b \in G ∀ a , b ∈ G , a ⋅ b ∈ G 。
结合律 :∀ a , b , c ∈ G , ( a ⋅ b ) ⋅ c = a ⋅ ( b ⋅ c ) \forall a,b,c \in G,(a \cdot b) \cdot c=a \cdot (b \cdot c) ∀ a , b , c ∈ G , ( a ⋅ b ) ⋅ c = a ⋅ ( b ⋅ c ) 。
单位元 :∃ e ∈ G , ∀ a ∈ G , e ⋅ a = a ⋅ e = a \exist e \in G,\forall a \in G,e \cdot a=a \cdot e=a ∃ e ∈ G , ∀ a ∈ G , e ⋅ a = a ⋅ e = a 。
逆元 :∀ a ∈ G , ∃ b ∈ G , a ⋅ b = b ⋅ a = e \forall a \in G,\exist b \in G,a \cdot b=b \cdot a=e ∀ a ∈ G , ∃ b ∈ G , a ⋅ b = b ⋅ a = e ,记作 b = a − 1 b=a^{-1} b = a − 1 。
如果一个群 G G G 的元素数量是有限的,那么它就是有限群 ,它的元素数量叫做它的阶 ,记作 ∣ G ∣ \lvert G\rvert ∣ G ∣ 。
对于有限群 G G G ,如果 H ⊆ G H \subseteq G H ⊆ G ,并且 G , H G,H G , H 的运算相同,则称 H H H 为 G G G 的子群 。
对于 a ∈ G a \in G a ∈ G ,使 a k = e a^k=e a k = e 成立的最小正整数 k k k 称作 a a a 的阶,记作 ord ( a ) \operatorname{ord}(a) ord ( a ) 。
拉格朗日定理
对于有限群 G G G ,若 H H H 为 G G G 的子群,则 ∣ H ∣ ∣ ∣ G ∣ \lvert H\rvert \mid \lvert G\rvert ∣ H ∣ ∣ ∣ G ∣ ,即 H H H 的阶整除 G G G 的阶。
以下证明中的 ⋅ \cdot ⋅ 运算符号省略。
∀ a ∈ G \forall a \in G ∀ a ∈ G ,定义左陪集:
a H = { a h ∣ h ∈ H } aH=\left\{ah \mid h\in H\right\}
a H = { ah ∣ h ∈ H }
a H aH a H 的元素与 H H H 一一对应,因此 ∣ a H ∣ = ∣ H ∣ \lvert aH\rvert=\lvert H\rvert ∣ a H ∣ = ∣ H ∣ 。
取两个不同的陪集 a H , b H aH,bH a H , b H ,假设它们有公共元素,即 ∃ h 1 , h 2 ∈ H , a h 1 = b h 2 \exist h_1,h_2 \in H,ah_1=bh_2 ∃ h 1 , h 2 ∈ H , a h 1 = b h 2 ,则 a = b h 2 h 1 − 1 a=b h_2h_1^{-1} a = b h 2 h 1 − 1 。
又因为 h 2 h 1 − 1 ∈ H h_2h_1^{-1}\in H h 2 h 1 − 1 ∈ H ,所以 a ∈ b H a\in bH a ∈ b H 。
∀ a h ∈ a H , a h = ( b h 2 h 1 − 1 ) h = b ( h 2 h 1 − 1 h ) ∈ b H \forall ah \in aH,ah=(bh_2h_1^{-1})h=b(h_2h_1^{-1}h)\in bH ∀ ah ∈ a H , ah = ( b h 2 h 1 − 1 ) h = b ( h 2 h 1 − 1 h ) ∈ b H ,所以 a H ⊆ b H aH \subseteq bH a H ⊆ b H 。
同理可证:b H ⊆ a H bH\subseteq aH b H ⊆ a H ,因此 a H = b H aH = bH a H = b H 。与假设“不同的陪集”矛盾,因此 a H , b H aH,bH a H , b H 不存在公共元素。
设不同的陪集有 k k k 个,可得:∣ G ∣ = k ∣ H ∣ \lvert G\rvert=k\lvert H\rvert ∣ G ∣ = k ∣ H ∣ 。即 ∣ H ∣ ∣ ∣ G ∣ \lvert H\rvert \mid \lvert G\rvert ∣ H ∣ ∣ ∣ G ∣ 。
推论:设 ∣ G ∣ = m \lvert G \rvert=m ∣ G ∣ = m ,∀ a ∈ G , a m = e \forall a \in G,a^m=e ∀ a ∈ G , a m = e 。
取 a a a 生成的循环子群 ⟨ a ⟩ = { a x ∣ x ∈ N } \langle a\rangle=\left\{a^x \mid x\in \mathbb{N}\right\} ⟨ a ⟩ = { a x ∣ x ∈ N } ,容易知道其阶等于 a a a 的阶,且为 G G G 的子群。由拉格朗日定理得:ord ( a ) ∣ m \operatorname{ord}(a) \mid m ord ( a ) ∣ m 。因此:
a m = ( a ord ( a ) ) m ord ( a ) = e m ord ( a ) = e a^m=(a^{\operatorname{ord}(a)})^{\frac{m}{\operatorname{ord}(a)}}=e^{\frac{m}{\operatorname{ord}(a)}}=e
a m = ( a ord ( a ) ) ord ( a ) m = e ord ( a ) m = e
费马小定理
若 p p p 为素数,且 p ∤ a p \nmid a p ∤ a ,则:
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p
a p − 1 ≡ 1 ( mod p )
令 G = ( Z / p Z ) × G=(\mathbb{Z}/p\mathbb{Z})^\times G = ( Z / p Z ) × (即所有与 p p p 互质的剩余类),易知 ∣ G ∣ = p − 1 \lvert G\rvert=p-1 ∣ G ∣ = p − 1 。
因为 p ∤ a p \nmid a p ∤ a ,所以 a ∈ G a \in G a ∈ G ,根据拉格朗日定理的推论,a ∣ G ∣ = e a^{\lvert G\rvert}=e a ∣ G ∣ = e ,即 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p a p − 1 ≡ 1 ( mod p ) 。
欧拉定理
若 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 ,则:
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1\pmod n
a φ ( n ) ≡ 1 ( mod n )
令 G = ( Z / n Z ) × G=(\mathbb{Z}/n\mathbb{Z})^\times G = ( Z / n Z ) × ,易知 ∣ G ∣ = φ ( n ) \lvert G\rvert=\varphi(n) ∣ G ∣ = φ ( n ) 。
因为 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 ,所以 a ∈ G a \in G a ∈ G ,a ∣ G ∣ = e a^{\lvert G\rvert}=e a ∣ G ∣ = e ,即 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1\pmod n a φ ( n ) ≡ 1 ( mod n ) 。
扩展欧拉定理
a b ≡ { a b m o d φ ( p ) gcd ( a , p ) = 1 a b gcd ( a , p ) ≠ 1 , b < φ ( p ) a ( b m o d φ ( p ) ) + φ ( p ) gcd ( a , p ) ≠ 1 , b ≥ φ ( p ) ( m o d p ) a^b \equiv \begin{cases}
a^{b\ \bmod\ \varphi(p)} & \gcd(a,p)=1 \\
a^b & \gcd(a,p) \neq 1,b<\varphi(p) \\
a^{(b\ \bmod\ \varphi(p))+\varphi(p)} & \gcd(a,p) \neq 1,b \geq \varphi(p)
\end{cases}
\pmod p
a b ≡ ⎩ ⎨ ⎧ a b mod φ ( p ) a b a ( b mod φ ( p )) + φ ( p ) g cd( a , p ) = 1 g cd( a , p ) = 1 , b < φ ( p ) g cd( a , p ) = 1 , b ≥ φ ( p ) ( mod p )
p p p 不一定是质数。
第一项就是欧拉定理,当 gcd ( a , p ) ≠ 1 \gcd(a,p) \neq 1 g cd( a , p ) = 1 的时候,把 p p p 质因数分解,对于每一个 p k p^k p k 证明原式成立,然后用 CRT 合并(CRT 见后文)即可。懒得证了。
裴蜀定理
若 a , b , c a,b,c a , b , c 均为整数,a x + b y = c ax+by=c a x + b y = c 存在整数解 ( x , y ) (x,y) ( x , y ) 当且仅当 gcd ( a , b ) ∣ c \gcd(a,b) \mid c g cd( a , b ) ∣ c 。
设 S = { a x + b y ∣ x , y ∈ Z , a x + b y > 0 } S=\left\{ax+by \mid x,y \in \mathbb{Z},ax+by>0\right\} S = { a x + b y ∣ x , y ∈ Z , a x + b y > 0 } ,易知 S S S 为 N + \mathbb{N^+} N + 的非空子集。设 S S S 中元素的最小值为 d d d 。容易知道必然存在整数 x , y x,y x , y 使得 d = a x + b y d=ax+by d = a x + b y 。
可以知道存在整数 q , r q,r q , r 满足 a = q d + r a=qd+r a = q d + r ,其中 0 ≤ r < d 0 \leq r<d 0 ≤ r < d 。
把 d d d 带入:r = a − q d = a − q ( a x + b y ) = a ( 1 − q x ) + b ( − q y ) r=a-qd=a-q(ax+by)=a(1-qx)+b(-qy) r = a − q d = a − q ( a x + b y ) = a ( 1 − q x ) + b ( − q y ) 。
如果 r > 0 r>0 r > 0 ,那么 r ∈ S r \in S r ∈ S 并且 r < d r<d r < d ,矛盾,因此 r = 0 r=0 r = 0 ,即 d ∣ a d \mid a d ∣ a 。
同理,可证:d ∣ b d \mid b d ∣ b 。因此 d d d 为 a , b a,b a , b 的公因数。
设 k k k 是 a , b a,b a , b 的一个公因数,可得 k ∣ d k \mid d k ∣ d ,即 k ≤ d k \leq d k ≤ d ,因此 d d d 为 a , b a,b a , b 的最大公因数,即 d = gcd ( a , b ) d=\gcd(a,b) d = g cd( a , b ) 。
设 m = c gcd ( a , b ) m=\frac{c}{\gcd(a,b)} m = g c d ( a , b ) c ,显然把 x , y x,y x , y 均乘上 m m m 就可以得到 a x + b y = c ax+by=c a x + b y = c 的解,所以 gcd ( a , b ) ∣ c \gcd(a,b) \mid c g cd( a , b ) ∣ c 的充分性得证;
因为 d = gcd ( a , b ) d=\gcd(a,b) d = g cd( a , b ) ,所以 d ∣ ( a x + b y ) d \mid (ax+by) d ∣ ( a x + b y ) ,即 d ∣ c d \mid c d ∣ c ,gcd ( a , b ) ∣ c \gcd(a,b) \mid c g cd( a , b ) ∣ c 的必要性得证。
所以,gcd ( a , b ) ∣ c \gcd(a,b)\mid c g cd( a , b ) ∣ c 是存在整数解的充要条件。
扩展欧几里得算法(exGCD)
求 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) a x + b y = g cd( a , b ) 的一组特解。
由裴蜀定理容易知道一定有解。
如果 b = 0 b=0 b = 0 ,gcd ( a , b ) = a \gcd(a,b)=a g cd( a , b ) = a ,此时 x = 1 , y = 0 x=1,y=0 x = 1 , y = 0 。
考虑 a a a 除以 b b b ,设 a = q b + r a=qb+r a = q b + r ,其中 0 ≤ r < b 0 \leq r<b 0 ≤ r < b 。可以推出 gcd ( a , b ) = gcd ( b , a m o d b ) = gcd ( b , r ) \gcd(a,b)=\gcd(b,a\bmod b)=\gcd(b,r) g cd( a , b ) = g cd( b , a mod b ) = g cd( b , r ) 。
设 gcd ( b , r ) \gcd(b,r) g cd( b , r ) 这一步返回了 x 0 , y 0 x_0,y_0 x 0 , y 0 ,得到:
b x 0 + r y 0 = gcd ( a , b ) b x 0 + ( a − q b ) y 0 = gcd ( a , b ) a y 0 + b ( x 0 − q y 0 ) = gcd ( a , b ) bx_0+ry_0=\gcd(a,b) \\
bx_0+(a-qb)y_0=\gcd(a,b) \\
ay_0+b(x_0-qy_0)=\gcd(a,b)
b x 0 + r y 0 = g cd( a , b ) b x 0 + ( a − q b ) y 0 = g cd( a , b ) a y 0 + b ( x 0 − q y 0 ) = g cd( a , b )
其中 q = ⌊ a b ⌋ q=\lfloor \frac{a}{b} \rfloor q = ⌊ b a ⌋ 。
显然我们可以令:
x 1 = y 0 , y 1 = x 0 − ⌊ a b ⌋ y 0 x_1=y_0,y_1=x_0-\lfloor \frac{a}{b}\rfloor y_0
x 1 = y 0 , y 1 = x 0 − ⌊ b a ⌋ y 0
显然第一步是正确的,后面每一步是由前一步推导出的,所以也都是正确的。
这就是扩展欧几里得算法的流程。
时间复杂度:O ( log ( a + b ) ) O(\log (a+b)) O ( log ( a + b )) 。
扩展中国剩余定理(exCRT)
普通 CRT 感觉不如 exCRT,不讲了。
给定 a i , m i a_i,m_i a i , m i ,解同余方程:
{ x ≡ a 1 ( m o d m 1 ) ⋯ x ≡ a n ( m o d m n ) \begin{cases}
x \equiv a_1 \pmod{m_1} \\
\cdots \\
x \equiv a_n \pmod{m_n}
\end{cases}
⎩ ⎨ ⎧ x ≡ a 1 ( mod m 1 ) ⋯ x ≡ a n ( mod m n )
m i m_i m i 不一定两两互质。
考虑两两合并,对于 x ≡ a 1 ( m o d m 1 ) x \equiv a_1\pmod{m_1} x ≡ a 1 ( mod m 1 ) 与 x ≡ a 2 ( m o d m 2 ) x\equiv a_2\pmod{m_2} x ≡ a 2 ( mod m 2 ) 。
这等价于:x = a 1 + y 1 m 1 x=a_1+y_1m_1 x = a 1 + y 1 m 1 与 x = a 2 + y 2 m 2 x=a_2+y_2m_2 x = a 2 + y 2 m 2 。带入:a 1 + y 1 m 1 = a 2 + y 2 m 2 a_1+y_1m_1=a_2+y_2m_2 a 1 + y 1 m 1 = a 2 + y 2 m 2 ,即 m 1 y 1 − m 2 y 2 = a 2 − a 1 m_1y_1-m_2y_2=a_2-a_1 m 1 y 1 − m 2 y 2 = a 2 − a 1 ,利用扩展欧几里得算法算出一组 ( y 1 , y 2 ) (y_1,y_2) ( y 1 , y 2 ) ,算不出来说明整个同余方程无解,算出来了就可以得到 x ≡ a 1 + y 1 m 1 ( m o d lcm ( m 1 , m 2 ) ) x\equiv a_1+y_1m_1\pmod{\operatorname{lcm}(m_1,m_2)} x ≡ a 1 + y 1 m 1 ( mod lcm ( m 1 , m 2 )) 。
时间复杂度:O ( n log M ) O(n \log M) O ( n log M ) 。
大步小步算法(BSGS)
解方程:a x ≡ b ( m o d p ) a^x \equiv b \pmod p a x ≡ b ( mod p ) ,a , p a,p a , p 互质。
设 m = ⌈ p ⌉ m=\lceil \sqrt{p}\rceil m = ⌈ p ⌉ ,得到 x = i m + j x=im+j x = im + j ,其中 0 ≤ i < m , 0 ≤ j < m 0 \leq i<m,0 \leq j<m 0 ≤ i < m , 0 ≤ j < m 。
带入:
a i m + j = b a j = b ( a − m ) i a^{im+j}=b \\
a^j=b(a^{-m})^i
a im + j = b a j = b ( a − m ) i
枚举 j j j ,计算 g j m o d p g^j \bmod p g j mod p 记下来,然后枚举 i i i ,计算 t = b ( a − m ) i ( m o d p ) t=b(a^{-m})^i \pmod p t = b ( a − m ) i ( mod p ) ,查找 t t t ,找到了就说明此时的 x x x 是解。如果最终都没找到,说明无解。
时间复杂度:O ( p ) O(\sqrt{p}) O ( p ) 。
扩展大步小步算法(exBSGS)
解方程:a x ≡ b ( m o d p ) a^x \equiv b\pmod{p} a x ≡ b ( mod p ) ,a , p a,p a , p 不一定互质。
首先把 a , b a,b a , b 取模,特判 p = 1 p=1 p = 1 或 b = 1 b=1 b = 1 的情况。
我们计算 d = gcd ( a , p ) d=\gcd(a,p) d = g cd( a , p ) ,如果 b m o d d ≠ 0 b \bmod d \neq 0 b mod d = 0 ,则无解。否则我们可以得到:a d a x − 1 ≡ b d ( m o d p d ) \frac{a}{d}a^{x-1}\equiv\frac{b}{d}\pmod{\frac{p}{d}} d a a x − 1 ≡ d b ( mod d p ) 。
令:
b ← b d p ← p d b \leftarrow \frac{b}{d} \\
p \leftarrow\frac{p}{d}
b ← d b p ← d p
不断进行上面的操作,直到 a , p a,p a , p 互质。设我们进行了 k k k 次操作,m m m 表示每一轮的 a d \frac{a}{d} d a 的乘积,则我们得到了:
m a x − k ≡ b ( m o d p ) a x − k ≡ b m − 1 ( m o d p ) ma^{x-k}\equiv b\pmod p \\
a^{x-k}\equiv bm^{-1}\pmod p
m a x − k ≡ b ( mod p ) a x − k ≡ b m − 1 ( mod p )
此时 a , p a,p a , p 互质,跑 BSGS 即可。
但是还有一种可能,就是答案 x < k x<k x < k ,所以在每次计算 d = gcd ( a , p ) d=\gcd(a,p) d = g cd( a , p ) 之前枚举 x = 0 , 1 , … , k − 1 x=0,1,\dots,k-1 x = 0 , 1 , … , k − 1 就好。
时间复杂度:O ( p ) O(\sqrt{p}) O ( p ) 。
Lucas 定理
设 p p p 为质数,则:
( n m ) ≡ ( ⌊ n p ⌋ ⌊ m p ⌋ ) ( n m o d p m m o d p ) ( m o d p ) \binom{n}{m}\equiv\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\binom{n\bmod p}{m\bmod p}\pmod p
( m n ) ≡ ( ⌊ p m ⌋ ⌊ p n ⌋ ) ( m mod p n mod p ) ( mod p )
考虑组合意义,设 n = q p + r , m = s p + t n=qp+r,m=sp+t n = qp + r , m = s p + t ,0 ≤ r < p , 0 ≤ t < p 0\leq r<p,0 \leq t<p 0 ≤ r < p , 0 ≤ t < p ,将 n n n 个球排成一圈,每 q q q 个分成一组,每组 p p p 个球,最终剩下 r r r 个球没有组。设这 q q q 组为 G 1 , G 2 , … , G q G_1,G_2,\dots,G_q G 1 , G 2 , … , G q ,没有组的为 G 0 G_0 G 0 。
考虑从 n n n 个球中选出 m m m 个,设在 G i G_i G i 中选了 k i k_i k i 个球(1 ≤ i ≤ q , 0 ≤ k i ≤ p , 0 ≤ k 0 ≤ r 1 \leq i \leq q,0 \leq k_i \leq p,0 \leq k_0 \leq r 1 ≤ i ≤ q , 0 ≤ k i ≤ p , 0 ≤ k 0 ≤ r ),则 ∑ k i + k 0 = m \sum k_i+k_0=m ∑ k i + k 0 = m ,总方案数为:
( n m ) ≡ ( r k 0 ) ∏ i = 1 q ( p k i ) ( m o d p ) \binom{n}{m}\equiv\binom{r}{k_0}\prod_{i=1}^q\binom{p}{k_i}\pmod p
( m n ) ≡ ( k 0 r ) i = 1 ∏ q ( k i p ) ( mod p )
假设 ∃ 1 ≤ i ≤ q , 1 ≤ k i ≤ p − 1 \exist 1 \leq i \leq q,1 \leq k_i \leq p-1 ∃1 ≤ i ≤ q , 1 ≤ k i ≤ p − 1 ,那么有 ( p k i ) ≡ 0 ( m o d p ) \binom{p}{k_i}\equiv0\pmod p ( k i p ) ≡ 0 ( mod p ) ,因此在总方案数中,它们没有贡献,我们只需考虑 k i = 0 k_i=0 k i = 0 或 k i = p k_i=p k i = p 的部分产生的贡献。又因为 m = s p + t m=sp+t m = s p + t ,所以一共有 s s s 个 k i = p k_i=p k i = p ,而 k 0 = t k_0=t k 0 = t 。所以总方案数为:
( q s ) ( r t ) \binom{q}{s}\binom{r}{t}
( s q ) ( t r )
因此:
( n m ) ≡ ( ⌊ n p ⌋ ⌊ m p ⌋ ) ( n m o d p m m o d p ) ( m o d p ) \binom{n}{m}\equiv\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\binom{n\bmod p}{m\bmod p}\pmod p
( m n ) ≡ ( ⌊ p m ⌋ ⌊ p n ⌋ ) ( m mod p n mod p ) ( mod p )
扩展 Lucas 定理(exLucas)
计算
( n m ) m o d p \binom{n}{m} \bmod p
( m n ) mod p
其中 p p p 不一定是质数。
我们考虑把 p p p 质因数分解,对于每一个 p k p^k p k 分别求解,最后用 CRT 或 exCRT 合并。
设 f ( n ) f(n) f ( n ) 表示在 n ! n! n ! 中,含有多少个质因子 p p p 。容易知道:
f ( n ) = ∑ i = 1 ∞ ⌊ n p i ⌋ = ⌊ n p ⌋ + f ( ⌊ n p ⌋ ) f(n)=\sum_{i=1}^\infin \lfloor\frac{n}{p^i}\rfloor=\lfloor\frac{n}{p}\rfloor+f(\lfloor \frac{n}{p}\rfloor)
f ( n ) = i = 1 ∑ ∞ ⌊ p i n ⌋ = ⌊ p n ⌋ + f (⌊ p n ⌋)
那么 ( n m ) \binom{n}{m} ( m n ) 中包含的质因子 p p p 的数量 c = f ( n ) − f ( m ) − f ( n − m ) c=f(n)-f(m)-f(n-m) c = f ( n ) − f ( m ) − f ( n − m ) 。
设 g ( n ) g(n) g ( n ) 表示在 n ! n! n ! 中,除以所有的 p p p 之后剩下的数对 p k p^k p k 取模结果。即:
g ( n ) = n ! p f ( n ) m o d p k g(n)=\frac{n!}{p^{f(n)}} \bmod p^k
g ( n ) = p f ( n ) n ! mod p k
推一些式子:
n ! = ( ∏ 1 ≤ i ≤ n , p ∤ i i ) ( ∏ i = 1 ⌊ n p ⌋ i ⋅ p ) = ( ∏ 1 ≤ i ≤ n , p ∤ i i ) p ⌊ n p ⌋ ( ⌊ n p ⌋ ! ) n!=\left(\prod_{1 \leq i \leq n,p \nmid i} i\right)\left(\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}i\cdot p\right) \\
=\left(\prod_{1\leq i\leq n,p \nmid i}i\right)p^{\lfloor\frac{n}{p}\rfloor}\left(\lfloor\frac{n}{p}\rfloor!\right)
n ! = 1 ≤ i ≤ n , p ∤ i ∏ i i = 1 ∏ ⌊ p n ⌋ i ⋅ p = 1 ≤ i ≤ n , p ∤ i ∏ i p ⌊ p n ⌋ ( ⌊ p n ⌋! )
两边同时除以 p f ( n ) p^{f(n)} p f ( n ) :
g ( n ) = ( ∏ 1 ≤ i ≤ n , p ∤ i i ) g ( ⌊ n p ⌋ ) g(n)=\left(\prod_{1\leq i\leq n,p \nmid i}i\right)g\left(\lfloor\frac{n}{p}\rfloor\right)
g ( n ) = 1 ≤ i ≤ n , p ∤ i ∏ i g ( ⌊ p n ⌋ )
其中 g ( 0 ) = 1 g(0)=1 g ( 0 ) = 1 。
考虑快速计算 ∏ 1 ≤ i ≤ n , p ∤ i i \prod_{1\leq i\leq n,p \nmid i}i ∏ 1 ≤ i ≤ n , p ∤ i i ,我们知道,x ≡ x + p k ( m o d p k ) x\equiv x+p^k \pmod{p^k} x ≡ x + p k ( mod p k ) ,因此我们可以仅仅计算从 1 1 1 到 n p k \frac{n}{p^k} p k n 部分中,不被 p p p 整除的数的乘积。对其求前缀积 h ( n ) h(n) h ( n ) 可得:
( ∏ 1 ≤ i ≤ n , p ∤ i i ) ≡ h ( p k ) ⌊ n p k ⌋ h ( n m o d ( p k ) ) ( m o d p k ) \left(\prod_{1\leq i\leq n,p \nmid i}i\right)\equiv h\left(p^k\right)^{\lfloor\frac{n}{p^k}\rfloor}h\left(n \bmod \left(p^k\right)\right) \pmod{p^k}
1 ≤ i ≤ n , p ∤ i ∏ i ≡ h ( p k ) ⌊ p k n ⌋ h ( n mod ( p k ) ) ( mod p k )
综合起来:
( n m ) ≡ p c g ( n ) g ( m ) − 1 g ( n − m ) − 1 ( m o d p k ) \binom{n}{m}\equiv p^cg(n)g(m)^{-1}g(n-m)^{-1} \pmod{p^k}
( m n ) ≡ p c g ( n ) g ( m ) − 1 g ( n − m ) − 1 ( mod p k )
然后 CRT 或 exCRT 合并,于是就做完了。时间复杂度:O ( p ) O(p) O ( p ) 。
整除分块
求:
∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^n \lfloor\frac{n}{i}\rfloor
i = 1 ∑ n ⌊ i n ⌋
性质:⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor ⌊ i n ⌋ 取值只有 O ( n ) O(\sqrt{n}) O ( n ) 种。
当 i ≤ n i \leq \sqrt{n} i ≤ n ,i i i 的取值最多 n \sqrt{n} n 个,因此原式取值最多 n \sqrt{n} n 个。
当 i > n i>\sqrt{n} i > n ,⌊ n i ⌋ < n \lfloor\frac{n}{i}\rfloor<\sqrt{n} ⌊ i n ⌋ < n ,取值最多 n \sqrt{n} n 个。
显然每种取值也是连续的。所以我们考虑对于每一段计算。
设当前段左端点为 l l l ,右端点为 r r r ,那么这一段的值为 v = ⌊ n l ⌋ v=\lfloor\frac{n}{l}\rfloor v = ⌊ l n ⌋ ,r r r 为满足 ⌊ n r ⌋ = v \lfloor\frac{n}{r}\rfloor=v ⌊ r n ⌋ = v 的最大整数。
有如下式子:
v ≤ n r < v + 1 r ≤ ⌊ n l ⌋ v\leq\frac{n}{r}<v+1 \\
r \leq \lfloor\frac{n}{l}\rfloor
v ≤ r n < v + 1 r ≤ ⌊ l n ⌋
因此 r = ⌊ n ⌊ n l ⌋ ⌋ r=\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor r = ⌊ ⌊ l n ⌋ n ⌋ 。
时间复杂度:O ( n ) O(\sqrt{n}) O ( n ) 。
如果所求式子带权:
∑ i = 1 n f ( i ) ⌊ n i ⌋ \sum_{i=1}^n f(i)\lfloor\frac{n}{i}\rfloor
i = 1 ∑ n f ( i ) ⌊ i n ⌋
处理 f f f 的前缀和,每一段乘上 f f f 的区间和即可。
如果是二维整除分块:
∑ i = 1 min ( n , m ) ⌊ n i ⌋ ⌊ m i ⌋ \sum_{i=1}^{\min(n,m)}\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor
i = 1 ∑ m i n ( n , m ) ⌊ i n ⌋ ⌊ i m ⌋
其他部分不变,只考虑 r r r 怎么求。类似上面的式子推一下就能得到:r = min ( ⌊ n ⌊ n l ⌋ ⌋ , ⌊ m ⌊ m l ⌋ ⌋ ) r=\min\left(\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor,\lfloor\frac{m}{\lfloor\frac{m}{l}\rfloor}\rfloor\right) r = min ( ⌊ ⌊ l n ⌋ n ⌋ , ⌊ ⌊ l m ⌋ m ⌋ ) 。
k k k 维类似。时间复杂度 O ( k n ) O(k\sqrt{n}) O ( k n ) 。
莫比乌斯反演
μ ( n ) = { 1 n = 1 ( − 1 ) k n = p 1 p 2 p 3 … p k , ∀ 1 ≤ i ≤ k , p i ∈ P , ∀ 1 ≤ i < j ≤ k , p i ≠ p j 0 ∃ p ∈ P , p 2 ∣ n \mu(n)=\begin{cases}1&n=1\\(-1)^k&n=p_1p_2p_3\dots p_k,\forall 1 \leq i \leq k,p_i\in\mathbb{P},\forall 1 \leq i<j \leq k,p_i \neq p_j \\0 & \exist p \in \mathbb{P},p^2 \mid n\end{cases}
μ ( n ) = ⎩ ⎨ ⎧ 1 ( − 1 ) k 0 n = 1 n = p 1 p 2 p 3 … p k , ∀1 ≤ i ≤ k , p i ∈ P , ∀1 ≤ i < j ≤ k , p i = p j ∃ p ∈ P , p 2 ∣ n
意思就是,如果 n = 1 n=1 n = 1 ,那么 μ ( n ) = 1 \mu(n)=1 μ ( n ) = 1 ;如果 n n n 的质因数分解中有 k k k 个质因子,并且指数都为 1 1 1 ,那么 μ ( n ) = ( − 1 ) k \mu(n)=(-1)^k μ ( n ) = ( − 1 ) k ;否则 μ ( n ) = 0 \mu(n)=0 μ ( n ) = 0 。
性质:
∑ d ∣ n μ ( d ) = { 1 n = 1 0 n ≠ 1 \sum_{d \mid n}\mu(d)=\begin{cases}1&n=1\\0&n\neq1\end{cases}
d ∣ n ∑ μ ( d ) = { 1 0 n = 1 n = 1
首先第一项是显然的,我们证明第二项。
容易发现形如 ∏ i = 1 k p i \prod_{i=1}^k p_i ∏ i = 1 k p i 形式的 d d d 才是有贡献的。设 n n n 有 k k k 个不同的质因子,我们从中选取若干个组成了 d d d 。如果选取了偶数个,则 μ ( d ) = 1 \mu(d)=1 μ ( d ) = 1 ,如果选取了奇数个,则 μ ( d ) = − 1 \mu(d)=-1 μ ( d ) = − 1 。
设这 k k k 个不同的质因子中有一个特殊质因子 p p p 。我们先在其他 k − 1 k-1 k − 1 个质因子中选取,最后决定选不选 p p p 。显然,最后选 p p p 的方案数与不选 p p p 的方案数相同,但是对于同一种选取其他质因子的方案,选不选 p p p 之后的集合大小奇偶性不同。因此,选取偶数个的方案数等于选取奇数个的方案数。也就是 ∑ d ∣ n μ ( d ) = 0 ( n ≠ 1 ) \sum_{d \mid n}\mu(d)=0\ (n\neq1) ∑ d ∣ n μ ( d ) = 0 ( n = 1 ) 。
假设我们已知:
f ( n ) = ∑ n ∣ d g ( d ) f(n)=\sum_{n \mid d} g(d)
f ( n ) = n ∣ d ∑ g ( d )
那么根据反演有:
g ( n ) = ∑ n ∣ d μ ( d n ) f ( d ) g(n)=\sum_{n\mid d}\mu\left(\frac{d}{n}\right)f(d)
g ( n ) = n ∣ d ∑ μ ( n d ) f ( d )
∑ n ∣ d μ ( d n ) f ( d ) = ∑ n ∣ d μ ( d n ) ∑ d ∣ k g ( k ) \sum_{n\mid d}\mu\left(\frac{d}{n}\right)f(d)=\sum_{n \mid d}\mu\left(\frac{d}{n}\right)\sum_{d \mid k}g(k)
n ∣ d ∑ μ ( n d ) f ( d ) = n ∣ d ∑ μ ( n d ) d ∣ k ∑ g ( k )
令 t = d n t=\frac{d}{n} t = n d ,有:
∑ n ∣ d μ ( d n ) ∑ d ∣ k g ( k ) = ∑ n ∣ k g ( k ) ∑ t ∣ k n μ ( t ) = ∑ n ∣ k g ( k ) [ k n = 1 ] = g ( n ) \sum_{n \mid d}\mu\left(\frac{d}{n}\right)\sum_{d \mid k}g(k)=\sum_{n \mid k}g(k)\sum_{t \mid \frac{k}{n}} \mu(t)=\sum_{n\mid k}g(k)\left[\frac{k}{n}=1\right]=g(n)
n ∣ d ∑ μ ( n d ) d ∣ k ∑ g ( k ) = n ∣ k ∑ g ( k ) t ∣ n k ∑ μ ( t ) = n ∣ k ∑ g ( k ) [ n k = 1 ] = g ( n )
得证。
μ ( n ) \mu(n) μ ( n ) 一般使用线性筛求出,代码如下:
mu[1 ]=1 ;
for (int i=2 ;i<=n;i++){
if (!isp[i]){
prm[++pcnt]=i;
mu[i]=-1 ;
}
for (int j=1 ;j<=pcnt&&i*prm[j]<=n;j++){
isp[i*prm[j]]=true ;
if (i%prm[j]==0 ){
mu[i*prm[j]]=0 ;
break ;
}
else mu[i*prm[j]]=-mu[i];
}
}
例题
求 a b m o d m a^b \bmod m a b mod m ,1 ≤ a ≤ 1 0 9 , 1 ≤ b ≤ 1 0 20000000 , 1 ≤ m ≤ 1 0 8 1 \leq a\leq 10^9,1 \leq b \leq 10^{20000000},1 \leq m \leq 10^8 1 ≤ a ≤ 1 0 9 , 1 ≤ b ≤ 1 0 20000000 , 1 ≤ m ≤ 1 0 8 。
模板不讲了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll a,m,mod,x,p;
bool flag;
string b;
ll qpow (ll a,ll b) {
ll res=1 %mod;
while (b){
if (b&1 ) res=res*a%mod;
a=a*a%mod;
b>>=1 ;
}
return res;
}
int main () {
ios::sync_with_stdio (false );
cin.tie (0 );
cout.tie (0 );
cin>>a>>m>>b;
a%=m;
p=mod=m;
for (ll i=2 ;i*i<=m;i++){
if (m%i==0 ){
p=p/i*(i-1 );
while (m%i==0 ) m/=i;
}
}
if (m>1 ) p=p/m*(m-1 );
for (auto &i:b){
x=x*10 +i-'0' ;
if (x>=p){
flag=true ;
x%=p;
}
}
if (flag) x+=p;
cout<<qpow (a,x);
return 0 ;
}
给定不定方程 a x + b y = c ax+by=c a x + b y = c ,无解输出 − 1 -1 − 1 ;有正整数解输出正整数解数量,正整数解中 x x x 的最小值、最大值,正整数解中 y y y 的最小值、最大值;无正整数解有整数解输出整数解中 x x x 的最小正整数值,y y y 的最小正整数值。
判无解用裴蜀定理,求特解 x 0 , y 0 x_0,y_0 x 0 , y 0 使用 exgcd,考虑推出通解形式。有:
a ( x 0 + d b ) + b ( y 0 − d a ) = c a(x_0+db)+b(y_0-da)=c
a ( x 0 + d b ) + b ( y 0 − d a ) = c
其中 d b , d a db,da d b , d a 为整数。所以,最小的 d = 1 gcd ( a , b ) d=\frac{1}{\gcd(a,b)} d = g c d ( a , b ) 1 。令 d 1 = b gcd ( a , b ) , d 2 = a gcd ( a , b ) d_1=\frac{b}{\gcd(a,b)},d_2=\frac{a}{\gcd(a,b)} d 1 = g c d ( a , b ) b , d 2 = g c d ( a , b ) a ,s s s 为整数,有通解:
x = x 0 + s d 1 , y = y 0 − s d 2 x=x_0+sd_1, y=y_0-sd_2
x = x 0 + s d 1 , y = y 0 − s d 2
当 x x x 为正整数时,有 x > 0 x>0 x > 0 ,即:
x 0 + s d 1 > 0 → s > − x 0 d 1 x_0+sd_1>0 \rightarrow s>-\frac{x_0}{d_1}
x 0 + s d 1 > 0 → s > − d 1 x 0
当 y y y 为正整数时,有 y > 0 y>0 y > 0 ,即:
y 0 − s d 2 > 0 → s < y 0 d 2 y_0-sd_2>0 \rightarrow s<\frac{y_0}{d_2}
y 0 − s d 2 > 0 → s < d 2 y 0
分类讨论即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define getx(n) (x+(n)*d1)
#define gety(n) (y-(n)*d2)
LL _,a,b,c,x,y,g,d1,d2;
void read (LL &x) {
x=0 ;
char ch=getchar ();
int f=1 ;
while ((ch<'0' ||ch>'9' )&&ch!='-' ) ch=getchar ();
if (ch=='-' ){
f=-1 ;
ch=getchar ();
}
while (ch>='0' &&ch<='9' ){
x=x*10 +(ch^48 );
ch=getchar ();
}
x*=f;
return ;
}
void write (const LL &x) {
if (x<0 ){
putchar ('-' );
write (-x);
return ;
}
if (x<=9 ){
putchar (x^48 );
return ;
}
write (x/10 );
putchar (x%10 ^48 );
return ;
}
LL div1 (const LL &a,const LL &b) {
if (a%b&&(a<0 &&b>0 ||a>0 &&b<0 )) return a/b-1 ;
return a/b;
}
LL div2 (const LL &a,const LL &b) {return -div1 (-a,b);}
LL exgcd (const LL &a,const LL &b,LL &x,LL &y) {
if (b==0 ){
x=1 ,y=0 ;
return a;
}
LL g=exgcd (b,a%b,y,x);
y-=a/b*x;
return g;
}
void solve () {
read (a);
read (b);
read (c);
g=exgcd (a,b,x,y);
if (c%g){
printf ("-1\n" );
return ;
}
x*=c/g,y*=c/g;
d1=b/g,d2=a/g;
if (div2 (y,d2)-1 -div1 (-x,d1)<=0 ){
write (getx (div1 (-x,d1)+1 ));
putchar (' ' );
write (gety (div2 (y,d2)-1 ));
putchar ('\n' );;
}
else {
write (div2 (y,d2)-1 -div1 (-x,d1));
putchar (' ' );
write (getx (div1 (-x,d1)+1 ));
putchar (' ' );
write (gety (div2 (y,d2)-1 ));
putchar (' ' );
write (getx (div2 (y,d2)-1 ));
putchar (' ' );
write (gety (div1 (-x,d1)+1 ));
putchar ('\n' );
}
return ;
}
int main () {
read (_);
while (_--) solve ();
return 0 ;
}
有 n n n 条龙,m m m 把剑,你需要按顺序屠龙。每次屠龙,你需要选择攻击力不高于龙血量 a i a_i a i 的一把攻击力最高的剑,如果没有选取攻击力最低的,并攻击龙 x x x 次。设本次攻击力为 b i b_i b i ,则你需要满足 b i x ≡ a i ( m o d p i ) b_ix \equiv a_i\pmod{p_i} b i x ≡ a i ( mod p i ) ,并且 b i x ≥ a i b_ix\geq a_i b i x ≥ a i 。击败这只龙之后你会获得一把新的剑,旧的剑消失。求最小的正整数 x x x 或者报告无解。
我们先不考虑这个同余式和不等式,思考应该怎么选剑。显然,我们可以用一个 multiset 和二分查找完成。这样我们就确定了每一个 b i b_i b i 。然后我们跑一个 exCRT 求出最小的 x x x ,再利用通解公式求出满足不等式的最小解即可。
简单说一下怎么求通解。设 P = lcm i = 1 n ( p i ) P=\operatorname{lcm}_{i=1}^n(p_i) P = lcm i = 1 n ( p i ) ,我们求出来的解为 x 0 x_0 x 0 ,则有:
x 0 ≡ C ( m o d P ) x ≡ C ( m o d P ) x_0\equiv C\pmod P \\
x\equiv C\pmod P
x 0 ≡ C ( mod P ) x ≡ C ( mod P )
求出 C C C ,可以得到:x = s P + C x=sP+C x = s P + C ,其中 s s s 为整数。假设不等式的解集为 x ≥ T x \geq T x ≥ T ,则 s P + C ≥ T sP+C \geq T s P + C ≥ T ,s ≥ ⌈ T − C P ⌉ s \geq \lceil\frac{T-C}{P}\rceil s ≥ ⌈ P T − C ⌉ ,答案即为 ⌈ T − C P ⌉ P + C \lceil\frac{T-C}{P}\rceil P+C ⌈ P T − C ⌉ P + C 。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=1e5 +15 ;
ll _,n,m,atk,lcm,low,m1,m2,g,c,x,y,ans;
ll a[MAXN],p[MAXN],q[MAXN],b[MAXN];
multiset<ll> mset;
void exgcd (const ll &a,const ll &b,ll &x,ll &y) {
if (b==0 ){
x=1 ,y=0 ;
return ;
}
exgcd (b,a%b,y,x);
y-=a/b*x;
return ;
}
ll inv (const ll &a,const ll &mod) {
ll x,y;
exgcd (a,mod,x,y);
return (x%mod+mod)%mod;
}
void solve () {
mset.clear ();
cin>>n>>m;
for (ll i=1 ;i<=n;i++) cin>>a[i];
for (ll i=1 ;i<=n;i++) cin>>p[i];
for (ll i=1 ;i<=n;i++) cin>>q[i];
for (ll i=1 ;i<=m;i++){
cin>>atk;
mset.insert (atk);
}
for (ll i=1 ;i<=n;i++){
auto it=mset.upper_bound (a[i]);
if (it!=mset.begin ()) it--;
b[i]=*it;
mset.erase (it);
mset.insert (q[i]);
}
lcm=1 ,low=ans=0 ;
for (ll i=1 ;i<=n;i++){
low=max ((a[i]+b[i]-1 )/b[i],low);
g=__gcd(b[i],p[i]);
if (a[i]%g){
cout<<"-1\n" ;
return ;
}
a[i]/=g,b[i]/=g,p[i]/=g;
a[i]=(__int128)a[i]%p[i]*inv (b[i]%p[i],p[i])%p[i];
m1=lcm,m2=p[i];
g=__gcd(m1,m2);
c=a[i]-ans;
if (c%g){
cout<<"-1\n" ;
return ;
}
m1/=g,m2/=g,c/=g;
exgcd (m1,m2,x,y);
lcm*=m2;
x=((__int128)x*c%m2+m2)%m2;
ans=((__int128)x*g%lcm*m1%lcm+ans)%lcm;
}
if (ans<low){
low=(low-ans+lcm-1 )/lcm;
ans+=low*lcm;
}
cout<<ans<<'\n' ;
return ;
}
int main () {
ios::sync_with_stdio (false );
cin.tie (0 );
cout.tie (0 );
cin>>_;
while (_--) solve ();
return 0 ;
}
求:
∑ i = 0 k ( n i ) m o d 2333 \sum_{i=0}^k \binom{n}{i} \bmod 2333
i = 0 ∑ k ( i n ) mod 2333
设 p = 2333 p=2333 p = 2333 ,再设函数 f f f :
f ( n , k ) = ∑ i = 0 k ( n i ) m o d p = ∑ i = 0 k ( ⌊ n p ⌋ ⌊ i p ⌋ ) ( n m o d p i m o d p ) m o d p = ( ∑ i = 0 ⌊ k p ⌋ − 1 ( ⌊ n p ⌋ i ) ( ∑ j = 0 p − 1 ( n m o d p j ) ) + ( ⌊ n p ⌋ ⌊ k p ⌋ ) ( ∑ j = 0 k m o d p ( n m o d p j ) ) ) m o d p = ( 2 n m o d p ∑ i = 0 ⌊ k p ⌋ − 1 ( ⌊ n p ⌋ i ) + ( ⌊ n p ⌋ ⌊ k p ⌋ ) ( ∑ j = 0 k m o d p ( n m o d p j ) ) ) m o d p = ( 2 n m o d p f ( ⌊ n p ⌋ , ⌊ k p ⌋ − 1 ) + ( ⌊ n p ⌋ ⌊ k p ⌋ ) ( ∑ j = 0 k m o d p ( n m o d p j ) ) ) m o d p f(n,k)=\sum_{i=0}^k \binom{n}{i} \bmod p \\
=\sum_{i=0}^k \binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{i}{p}\rfloor}\binom{n \bmod p}{i \bmod p}\bmod p \\
=\left(\sum_{i=0}^{\left\lfloor\frac{k}{p}\right\rfloor-1}\binom{\lfloor\frac{n}{p}\rfloor}{i}\left(\sum_{j=0}^{p-1}\binom{n \bmod p}{j}\right)+\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{k}{p}\rfloor}\left(\sum_{j=0}^{k\ \bmod\ p}\binom{n \bmod p}{j}\right)\right) \bmod p \\
=\left(2^{n\ \bmod\ p}\sum_{i=0}^{\left\lfloor\frac{k}{p}\right\rfloor-1}\binom{\lfloor\frac{n}{p}\rfloor}{i}+\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{k}{p}\rfloor}\left(\sum_{j=0}^{k\ \bmod\ p}\binom{n \bmod p}{j}\right)\right) \bmod p \\
=\left(2^{n\ \bmod\ p}f\left(\left\lfloor\frac{n}{p}\right\rfloor,\left\lfloor\frac{k}{p}\right\rfloor-1\right)+\binom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{k}{p}\rfloor}\left(\sum_{j=0}^{k\ \bmod\ p}\binom{n \bmod p}{j}\right)\right) \bmod p
f ( n , k ) = i = 0 ∑ k ( i n ) mod p = i = 0 ∑ k ( ⌊ p i ⌋ ⌊ p n ⌋ ) ( i mod p n mod p ) mod p = i = 0 ∑ ⌊ p k ⌋ − 1 ( i ⌊ p n ⌋ ) ( j = 0 ∑ p − 1 ( j n mod p ) ) + ( ⌊ p k ⌋ ⌊ p n ⌋ ) ( j = 0 ∑ k mod p ( j n mod p ) ) mod p = 2 n mod p i = 0 ∑ ⌊ p k ⌋ − 1 ( i ⌊ p n ⌋ ) + ( ⌊ p k ⌋ ⌊ p n ⌋ ) ( j = 0 ∑ k mod p ( j n mod p ) ) mod p = ( 2 n mod p f ( ⌊ p n ⌋ , ⌊ p k ⌋ − 1 ) + ( ⌊ p k ⌋ ⌊ p n ⌋ ) ( j = 0 ∑ k mod p ( j n mod p ) ) ) mod p
加号后面的可以预处理前缀和,递归计算即可。
时间复杂度:O ( p 2 + T log p 2 n ) O(p^2+T\log_p^2n) O ( p 2 + T log p 2 n ) 。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=3005 ,MOD=2333 ;
ll _,n,k;
ll fact[MAXN],invfac[MAXN],pows[MAXN],pre[MAXN][MAXN];
ll qpow (ll a,ll b) {
ll res=1 ;
while (b){
if (b&1 ) res=res*a%MOD;
a=a*a%MOD;
b>>=1 ;
}
return res;
}
ll C (const ll &n,const ll &m) {
if (m<0 ||n<m) return 0 ;
return fact[n]*invfac[m]%MOD*invfac[n-m]%MOD;
}
void init () {
fact[0 ]=1 ;
for (ll i=1 ;i<MOD;i++) fact[i]=i*fact[i-1 ]%MOD;
invfac[MOD-1 ]=qpow (fact[MOD-1 ],MOD-2 );
for (ll i=MOD-1 ;i;i--) invfac[i-1 ]=i*invfac[i]%MOD;
pows[0 ]=1 ;
for (ll i=1 ;i<MOD;i++) pows[i]=pows[i-1 ]*2 %MOD;
for (int i=0 ;i<MOD;i++){
pre[i][0 ]=1 ;
for (int j=1 ;j<MOD;j++) pre[i][j]=(pre[i][j-1 ]+C (i,j))%MOD;
}
return ;
}
ll lucas (const ll &n,const ll &m) {
if (m<0 ||n<m) return 0 ;
if (n<MOD) return C (n,m);
return lucas (n/MOD,m/MOD)*lucas (n%MOD,m%MOD)%MOD;
}
ll f (const ll &n,const ll &k) {
ll res=0 ;
if (n<MOD){
for (ll i=0 ;i<=min (k,MOD-1 );i++) res=(res+C (n,i))%MOD;
return res;
}
res=pows[n%MOD]*f (n/MOD,k/MOD-1 );
res=(res+lucas (n/MOD,k/MOD)*pre[n%MOD][k%MOD]%MOD)%MOD;
return res;
}
void solve () {
cin>>n>>k;
k=min (n,k);
cout<<f (n,k)<<'\n' ;
return ;
}
int main () {
cin>>_;
init ();
while (_--) solve ();
return 0 ;
}
给定长度为 n n n 的序列 a a a ,求有多少个长度至少为 2 2 2 的不升子序列 a ′ a' a ′ 满足:
∏ i = 2 k ( a i − 1 ′ a i ′ ) ≡ 1 ( m o d 2 ) \prod_{i=2}^k \binom{a'_{i-1}}{a'_{i}}\equiv1\pmod 2
i = 2 ∏ k ( a i ′ a i − 1 ′ ) ≡ 1 ( mod 2 )
求出结果对 1 0 9 + 7 10^9+7 1 0 9 + 7 取模。
首先根据 Lucas 定理有:
∏ i = 2 k ( a i − 1 ′ a i ′ ) m o d 2 = ∏ i = 2 k ( ⌊ a i − 1 ′ 2 ⌋ ⌊ a i ′ 2 ⌋ ) ( a i − 1 ′ m o d 2 a i ′ m o d 2 ) m o d 2 > 0 \prod_{i=2}^k \binom{a'_{i-1}}{a'_{i}}\bmod 2 \\
=\prod_{i=2}^k\binom{\left\lfloor\frac{a'_{i-1}}{2}\right\rfloor}{\left\lfloor\frac{a'_{i}}{2}\right\rfloor}\binom{a'_{i-1}\bmod2}{a'_i\bmod2}\bmod2>0
i = 2 ∏ k ( a i ′ a i − 1 ′ ) mod 2 = i = 2 ∏ k ( ⌊ 2 a i ′ ⌋ ⌊ 2 a i − 1 ′ ⌋ ) ( a i ′ mod 2 a i − 1 ′ mod 2 ) mod 2 > 0
说明 ( a i − 1 ′ m o d 2 a i ′ m o d 2 ) = 1 \binom{a'_{i-1}\ \bmod\ 2}{a'_i\ \bmod\ 2}=1 ( a i ′ mod 2 a i − 1 ′ mod 2 ) = 1 。
继续展开左边的这一坨分式,我们发现整体式子非 0 0 0 当且仅当 a i − 1 ′ a'_{i-1} a i − 1 ′ 与 a i ′ a'_i a i ′ 在二进制每一位上 a i − 1 , j ′ ≥ a i , j ′ a'_{i-1,j}\geq a'_{i,j} a i − 1 , j ′ ≥ a i , j ′ 成立。也就是定义 & \& & 表示按位与,a i − 1 ′ & a i ′ = a i ′ a'_{i-1}\&a'_{i}=a'_i a i − 1 ′ & a i ′ = a i ′ 。这也可以看作 a i ′ a'_i a i ′ 是 a i − 1 ′ a'_{i-1} a i − 1 ′ 的子集。
注意到 a i a_i a i 互不相同,设 d p i dp_i d p i 表示结尾是 i i i 的序列数量,枚举子集 j j j 刷表法转移即可。
时间复杂度:O ( 3 log 2 max a i ) O(3^{\log_2\max a_i}) O ( 3 l o g 2 m a x a i ) 。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=1e6 +16 ,MOD=1e9 +7 ;
ll n,ans;
ll a[MAXN],dp[MAXN];
int main () {
cin>>n;
for (ll i=1 ;i<=n;i++){
cin>>a[i];
for (ll j=a[i]&a[i]-1 ;j;j=j-1 &a[i]) dp[j]=(dp[j]+dp[a[i]]+1 )%MOD;
ans=(ans+dp[a[i]])%MOD;
}
cout<<ans;
return 0 ;
}
求:
∑ i = 1 n ∑ j = 1 m ( n m o d i ) ( m m o d j ) , i ≠ j \sum_{i=1}^n\sum_{j=1}^m(n\bmod i)(m\bmod j),i\neq j
i = 1 ∑ n j = 1 ∑ m ( n mod i ) ( m mod j ) , i = j
规定 n ≤ m n\leq m n ≤ m ,容易想到把取模变成整除形式:
∑ i = 1 n ∑ j = 1 m ( n m o d i ) ( m m o d j ) , i ≠ j = ∑ i = 1 n ∑ j = 1 m ( n − i ⌊ n i ⌋ ) ( m − j ⌊ m j ⌋ ) − ∑ i = 1 n ( n − i ⌊ n i ⌋ ) ( m − i ⌊ m i ⌋ ) = ∑ i = 1 n ∑ j = 1 m n m − m i ⌊ n i ⌋ − n j ⌊ m j ⌋ + i j ⌊ n i ⌋ ⌊ m j ⌋ − ∑ i = 1 n n m − m i ⌊ n i ⌋ − n i ⌊ m i ⌋ + i 2 ⌊ n i ⌋ ⌊ m i ⌋ = n 2 m 2 − n 2 m − m 2 ∑ i = 1 n i ⌊ n i ⌋ − n 2 ∑ i = 1 m i ⌊ m i ⌋ + ( ∑ i = 1 n i ⌊ n i ⌋ ) ( ∑ i = 1 m i ⌊ m i ⌋ ) + m ∑ i = 1 n i ⌊ n i ⌋ + n ∑ i = 1 n i ⌊ m i ⌋ − ∑ i = 1 n i 2 ⌊ n i ⌋ ⌊ m i ⌋ \sum_{i=1}^n\sum_{j=1}^m(n\bmod i)(m\bmod j),i\neq j \\
=\sum_{i=1}^n\sum_{j=1}^m\left(n-i\left\lfloor\frac{n}{i}\right\rfloor\right)\left(m-j\left\lfloor\frac{m}{j}\right\rfloor\right)-\sum_{i=1}^{n}\left(n-i\left\lfloor\frac{n}{i}\right\rfloor\right)\left(m-i\left\lfloor\frac{m}{i}\right\rfloor\right) \\
=\sum_{i=1}^n\sum_{j=1}^m nm-mi\left\lfloor\frac{n}{i}\right\rfloor-nj\left\lfloor\frac{m}{j}\right\rfloor+ij\left\lfloor\frac{n}{i}\right\rfloor \left\lfloor\frac{m}{j}\right\rfloor-\sum_{i=1}^n nm-mi\left\lfloor\frac{n}{i}\right\rfloor-ni\left\lfloor\frac{m}{i}\right\rfloor+i^2\left\lfloor\frac{n}{i}\right\rfloor \left\lfloor\frac{m}{i}\right\rfloor \\
=n^2m^2-n^2m-m^2\sum_{i=1}^n i\left\lfloor\frac{n}{i}\right\rfloor-n^2\sum_{i=1}^m i\left\lfloor\frac{m}{i}\right\rfloor+\left(\sum_{i=1}^n i\left\lfloor\frac{n}{i}\right\rfloor\right)\left(\sum_{i=1}^mi\left\lfloor\frac{m}{i}\right\rfloor\right)+m\sum_{i=1}^ni\left\lfloor\frac{n}{i}\right\rfloor+n\sum_{i=1}^ni\left\lfloor\frac{m}{i}\right\rfloor-\sum_{i=1}^ni^2\left\lfloor\frac{n}{i}\right\rfloor \left\lfloor\frac{m}{i}\right\rfloor
i = 1 ∑ n j = 1 ∑ m ( n mod i ) ( m mod j ) , i = j = i = 1 ∑ n j = 1 ∑ m ( n − i ⌊ i n ⌋ ) ( m − j ⌊ j m ⌋ ) − i = 1 ∑ n ( n − i ⌊ i n ⌋ ) ( m − i ⌊ i m ⌋ ) = i = 1 ∑ n j = 1 ∑ m nm − mi ⌊ i n ⌋ − nj ⌊ j m ⌋ + ij ⌊ i n ⌋ ⌊ j m ⌋ − i = 1 ∑ n nm − mi ⌊ i n ⌋ − ni ⌊ i m ⌋ + i 2 ⌊ i n ⌋ ⌊ i m ⌋ = n 2 m 2 − n 2 m − m 2 i = 1 ∑ n i ⌊ i n ⌋ − n 2 i = 1 ∑ m i ⌊ i m ⌋ + ( i = 1 ∑ n i ⌊ i n ⌋ ) ( i = 1 ∑ m i ⌊ i m ⌋ ) + m i = 1 ∑ n i ⌊ i n ⌋ + n i = 1 ∑ n i ⌊ i m ⌋ − i = 1 ∑ n i 2 ⌊ i n ⌋ ⌊ i m ⌋
我们知道:
∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^n i^2=\frac{n(n+1)(2n+1)}{6}
i = 1 ∑ n i 2 = 6 n ( n + 1 ) ( 2 n + 1 )
因此整除分块即可。注意一些循环边界。
时间复杂度:O ( n ) O(\sqrt{n}) O ( n ) 。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MOD=19940417 ;
ll n,m,ans,x,y;
int main () {
cin>>n>>m;
if (n>m) swap (n,m);
ans=n*n%MOD*m%MOD*m%MOD;
ans-=n*n%MOD*m%MOD;
ans=(ans%MOD+MOD)%MOD;
for (ll i=1 ,j=1 ;j<=n;i=j+1 ){
if (n/i==0 ) break ;
j=n/(n/i);
x=(x+n/i*((i+j)*(j-i+1 )/2 %MOD)%MOD)%MOD;
}
ans-=x*m%MOD*m%MOD;
ans=(ans%MOD+MOD)%MOD;
for (ll i=1 ,j=1 ;j<=m;i=j+1 ){
if (m/i==0 ) break ;
j=m/(m/i);
y=(y+m/i*((i+j)*(j-i+1 )/2 %MOD)%MOD)%MOD;
}
ans-=y*n%MOD*n%MOD;
ans=(ans%MOD+MOD)%MOD;
ans=(ans+x*y%MOD)%MOD;
ans=(ans+x*m%MOD)%MOD;
x=0 ;
for (ll i=1 ,j=1 ;i<=n;i=j+1 ){
if (m/i==0 ) break ;
j=min (n,m/(m/i));
x=(x+m/i*((i+j)*(j-i+1 )/2 %MOD)%MOD)%MOD;
}
ans=(ans+x*n%MOD)%MOD;
x=y=0 ;
for (ll i=1 ,j=1 ;j<=n;i=j+1 ){
if (n/i==0 ||m/i==0 ) break ;
j=min (n/(n/i),m/(m/i));
x=(__int128)j*(j+1 )*(j*2 +1 )/6 %MOD;
x-=(__int128)(i-1 )*i*((i-1 )*2 +1 )/6 %MOD;
x=(x%MOD+MOD)%MOD;
y=(y+(n/i)*(m/i)%MOD*x%MOD)%MOD;
}
ans=(ans-y+MOD)%MOD;
cout<<ans;
return 0 ;
}
给出 n n n 次询问,每次给定 a , b , c , d , k a,b,c,d,k a , b , c , d , k ,求:
∑ i = a b ∑ j = c d [ gcd ( i , j ) = k ] \sum_{i=a}^b\sum_{j=c}^d \left[\gcd(i,j)=k\right]
i = a ∑ b j = c ∑ d [ g cd( i , j ) = k ]
设:
f ( a , b , c , d ) = ∑ i = a b ∑ j = c d [ gcd ( i , j ) = k ] f(a,b,c,d)=\sum_{i=a}^b\sum_{j=c}^d \left[\gcd(i,j)=k\right]
f ( a , b , c , d ) = i = a ∑ b j = c ∑ d [ g cd( i , j ) = k ]
容斥则有:
a n s = f ( 1 , b , 1 , d ) − f ( 1 , a − 1 , 1 , d ) − f ( 1 , b , 1 , c − 1 ) + f ( 1 , a − 1 , 1 , c − 1 ) ans=f(1,b,1,d)-f(1,a-1,1,d)-f(1,b,1,c-1)+f(1,a-1,1,c-1)
an s = f ( 1 , b , 1 , d ) − f ( 1 , a − 1 , 1 , d ) − f ( 1 , b , 1 , c − 1 ) + f ( 1 , a − 1 , 1 , c − 1 )
钦定 n ≤ m n \leq m n ≤ m ,所以只需要求:
T ( n , m ) = ∑ i = 1 n ∑ j = 1 m [ gcd ( i , j ) = k ] T(n,m)=\sum_{i=1}^n\sum_{j=1}^m\left[\gcd(i,j)=k\right] \\
T ( n , m ) = i = 1 ∑ n j = 1 ∑ m [ g cd( i , j ) = k ]
设 F ( d ) F(d) F ( d ) 表示最大公约数为 d d d 的数对数量,G ( d ) G(d) G ( d ) 表示满足 d ∣ gcd ( i , j ) d\mid \gcd(i,j) d ∣ g cd( i , j ) 的数对数量。得到:
G ( d ) = ∑ d ∣ k F ( k ) G ( d ) = ⌊ n d ⌋ ⌊ m d ⌋ G(d)=\sum_{d\mid k}F(k) \\
G(d)=\left\lfloor\frac{n}{d}\right\rfloor\left\lfloor\frac{m}{d}\right\rfloor
G ( d ) = d ∣ k ∑ F ( k ) G ( d ) = ⌊ d n ⌋ ⌊ d m ⌋
明显的莫比乌斯反演:
F ( k ) = ∑ k ∣ d μ ( d k ) G ( d ) = ∑ i = 1 ⌊ n k ⌋ μ ( i ) ⌊ n k i ⌋ ⌊ m k i ⌋ F(k)=\sum_{k\mid d}\mu\left(\frac{d}{k}\right)G(d) \\
=\sum_{i=1}^{\left\lfloor\frac{n}{k}\right\rfloor}\mu(i)\left\lfloor\frac{n}{ki}\right\rfloor\left\lfloor\frac{m}{ki}\right\rfloor
F ( k ) = k ∣ d ∑ μ ( k d ) G ( d ) = i = 1 ∑ ⌊ k n ⌋ μ ( i ) ⌊ ki n ⌋ ⌊ ki m ⌋
令 N = ⌊ n k ⌋ , M = ⌊ m k ⌋ N=\left\lfloor\frac{n}{k}\right\rfloor,M=\left\lfloor\frac{m}{k}\right\rfloor N = ⌊ k n ⌋ , M = ⌊ k m ⌋ :
F ( k ) = ∑ i = 1 N μ ( i ) ⌊ N i ⌋ ⌊ M i ⌋ F(k)=\sum_{i=1}^{N}\mu(i)\left\lfloor\frac{N}{i}\right\rfloor\left\lfloor\frac{M}{i}\right\rfloor
F ( k ) = i = 1 ∑ N μ ( i ) ⌊ i N ⌋ ⌊ i M ⌋
整除分块即可。
时间复杂度:O ( N + n N ) O(N+n\sqrt{N}) O ( N + n N ) 。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll MAXN=5e4 +54 ;
ll _,a,b,c,d,k,pcnt;
ll mu[MAXN],pre[MAXN],prm[MAXN];
bool isp[MAXN];
void init () {
mu[1 ]=1 ;
for (ll i=2 ;i<=50000 ;i++){
if (!isp[i]){
prm[++pcnt]=i;
mu[i]=-1 ;
}
for (ll j=1 ;j<=pcnt&&i*prm[j]<=50000 ;j++){
isp[i*prm[j]]=true ;
if (i%prm[j]==0 ){
mu[i*prm[j]]=0 ;
break ;
}
else mu[i*prm[j]]=-mu[i];
}
}
for (ll i=1 ;i<=50000 ;i++) pre[i]=mu[i]+pre[i-1 ];
return ;
}
ll f (const ll &n,const ll &m) {
ll tn=n/k,tm=m/k,res=0 ;
if (tn>tm) swap (tn,tm);
for (ll i=1 ,j=1 ;i<=tn;i=j+1 ){
if (tn/i==0 ||tm/i==0 ) break ;
j=min (tn/(tn/i),tm/(tm/i));
res+=(pre[j]-pre[i-1 ])*(tn/i)*(tm/i);
}
return res;
}
void solve () {
cin>>a>>b>>c>>d>>k;
cout<<f (b,d)-f (a-1 ,d)-f (b,c-1 )+f (a-1 ,c-1 )<<'\n' ;
return ;
}
int main () {
init ();
cin>>_;
while (_--) solve ();
return 0 ;
}
求:
∑ i = 1 n ∑ j = 1 m isp ( gcd ( i , j ) ) \sum_{i=1}^n\sum_{j=1}^m\operatorname{isp}(\gcd(i,j))
i = 1 ∑ n j = 1 ∑ m isp ( g cd( i , j ))
其中 isp ( x ) \operatorname{isp}(x) isp ( x ) 表示 x x x 是否为质数。
依旧令 n ≤ m n\leq m n ≤ m ,推式子:
∑ i = 1 n ∑ j = 1 m isp ( gcd ( i , j ) ) = ∑ p ∈ P ∑ i = 1 n ∑ j = 1 m [ gcd ( i , j ) = p ] \sum_{i=1}^n\sum_{j=1}^m\operatorname{isp}(\gcd(i,j))\\
=\sum_{p\in\mathbb{P}}\sum_{i=1}^n\sum_{j=1}^m\left[\gcd(i,j)=p\right] \\
i = 1 ∑ n j = 1 ∑ m isp ( g cd( i , j )) = p ∈ P ∑ i = 1 ∑ n j = 1 ∑ m [ g cd( i , j ) = p ]
显然和上一题一模一样。令 N = ⌊ n p ⌋ , M = ⌊ m p ⌋ N=\left\lfloor\frac{n}{p}\right\rfloor,M=\left\lfloor\frac{m}{p}\right\rfloor N = ⌊ p n ⌋ , M = ⌊ p m ⌋ :
a n s = ∑ p ∈ P ∑ i = 1 N μ ( i ) ⌊ N i ⌋ ⌊ M i ⌋ = ∑ i = 1 n ⌊ n i ⌋ ⌊ m i ⌋ ( ∑ p ∣ i , p ∈ P μ ( i p ) ) ans=\sum_{p\in\mathbb{P}}\sum_{i=1}^{N}\mu(i)\left\lfloor\frac{N}{i}\right\rfloor\left\lfloor\frac{M}{i}\right\rfloor\\
=\sum_{i=1}^n\left\lfloor\frac{n}{i}\right\rfloor\left\lfloor\frac{m}{i}\right\rfloor\left(\sum_{p\mid i,p\in\mathbb{P}}\mu\left(\frac{i}{p}\right)\right)\\
an s = p ∈ P ∑ i = 1 ∑ N μ ( i ) ⌊ i N ⌋ ⌊ i M ⌋ = i = 1 ∑ n ⌊ i n ⌋ ⌊ i m ⌋ p ∣ i , p ∈ P ∑ μ ( p i )
右边的一坨令其为 f ( i ) f(i) f ( i ) ,预处理即可。
时间复杂度:O ( n log log n + T n ) O(n\log\log n+T\sqrt{n}) O ( n log log n + T n ) 。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7 +17 ;
int _,n,m,pcnt;
long long ans;
long long mu[MAXN],pre[MAXN],f[MAXN],prm[1000005 ];
bool isp[MAXN];
void init () {
mu[1 ]=1 ;
for (int i=2 ;i<MAXN;i++){
if (!isp[i]){
prm[++pcnt]=i;
mu[i]=-1 ;
}
for (int j=1 ;j<=pcnt&&i*prm[j]<MAXN;j++){
isp[i*prm[j]]=true ;
if (i%prm[j]==0 ){
mu[i*prm[j]]=0 ;
break ;
}
else mu[i*prm[j]]=-mu[i];
}
}
for (int i=1 ;i<=pcnt;i++) for (int j=prm[i];j<MAXN;j+=prm[i]) f[j]+=mu[j/prm[i]];
for (int i=1 ;i<MAXN;i++) pre[i]=f[i]+pre[i-1 ];
return ;
}
void solve () {
ans=0 ;
cin>>n>>m;
if (n>m) swap (n,m);
for (int i=1 ,j=1 ;i<=n;i=j+1 ){
if (n/i==0 ||m/i==0 ) break ;
j=min (n/(n/i),m/(m/i));
ans+=(pre[j]-pre[i-1 ])*(n/i)*(m/i);
}
cout<<ans<<'\n' ;
return ;
}
int main () {
init ();
cin>>_;
while (_--) solve ();
return 0 ;
}
有帮助,赞一个