UPD:类欧更新啦!
按照课件的知识点总结吧
数论一大堆公式打的我烦
众所周知,取模运算对于加法,减法,乘法都试用
( a % p + b % p ) % p = ( a + b ) % p (a\%p+b\%p)\%p=(a+b)\%p (a%p+b%p)%p=(a+b)%p
( a % p − b % p ) % p = ( a − b ) % p (a\%p-b\%p)\%p=(a-b)\%p (a%p−b%p)%p=(a−b)%p
( a % p ∗ b % p ) % p = ( a ∗ b ) % p (a\%p*b\%p)\%p=(a*b)\%p (a%p∗b%p)%p=(a∗b)%p
加法证明直接带余除法分解一下就行了,其他类似
为减少模的常数,通常试用减法法加速
int pw(int a, int b) {
int res = 1 ;
rep(; b; b >>= 1, a = 1ll * a * a % p) if (b & 1) res = 1ll * res * a % p ;
return res ;
}
int mul(int a, int b) {
int res = 0 ;
for(; b; b >>= 1, a = (ll)(a + a) % p) if (b & 1) res = (ll)(res + a) % p ;
return res ;
}
之后一个题目:HDU 5187
可以分类讨论:
所以答案就是 2 n − 2 2^n-2 2n−2,用快速乘和快速幂解决
如果 a a a是 b b b的约数,则 a ∣ b a|b a∣b
之后一些显然的性质:
算术基本定理:每个大于 1 的正整数都可以被唯一地写成若干素数的乘积(不考虑负数)
我们把一个数写成质数相乘的形式的式子称为质因子分解式
若 n = ∏ a i p i n=\prod_{}{a_i}^{p_i} n=∏aipi,则其约数个数 d ( n ) d(n) d(n)为 ∏ p i + 1 \prod_{}{p_i+1} ∏pi+1
素数理论:
素数是大于 1 的正整数,且除了 1 和它自身不能被其他正整数整除
素数无限定理:存在无穷多个素数,用反证法证明
线性筛素数:只让每个合数被它的最小质因子筛去,复杂度是 O ( n ) O(n) O(n)
void select(int n) {
for (int i = 2; i <= n; i++) f[i] = 1 ;
f[0] = f[1] = 0 ;
tot = 0 ;
for (int i = 2; i <= n; i++) {
if (!f[i]) continue ;
prime[++tot] = i ;
for (int j = 1; j <= tot && prime[j] * i <= n; j++) {
if (i * prime[j] > n) break ;
f[i * prime[j]] = 0 ;
if (i % prime[j] == 0) break ; //保证只被最小的质因数筛到
}
}
}
素数分布:
设函数 π ( x ) \pi(x) π(x)表示不超过正实数 x x x的素数个数
lim n → ∞ π ( x ) x log x = 1 \lim\limits_{n\to\infty}\frac{\pi(x)}{\frac{x}{\log_x}}=1 n→∞limlogxxπ(x)=1,也就是 π ( x ) ≈ x log x \pi(x)≈\frac{x}{\log_x} π(x)≈logxx
所以我们开数组时空间除以10就好了
定理: gcd ( a , b ) = gcd ( b , a % b ) \gcd(a,b)=\gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
证明:设 a = k b + r a=kb+r a=kb+r,则 r = a % b r=a\%b r=a%b
假设 d d d是 gcd ( a , b ) \gcd(a,b) gcd(a,b),则 d ∣ a , d ∣ b d|a,d|b d∣a,d∣b
而 r = a − k b r=a-kb r=a−kb,因此 d ∣ r d|r d∣r,因此d也是 gcd ( b , a % b ) \gcd(b,a\%b) gcd(b,a%b)
假设 d d d是 gcd ( b , a % b ) \gcd(b,a\%b) gcd(b,a%b),则 d ∣ b , d ∣ r d|b,d|r d∣b,d∣r
而 a = k b + r a=kb+r a=kb+r,因此 d ∣ a d|a d∣a,因此 d d d也是 gcd ( a , b ) \gcd(a,b) gcd(a,b)
因此 ( a , b ) (a,b) (a,b)与 ( b , a % b ) (b,a\%b) (b,a%b)的公约数相同,则其最大公约数也必定相同
int gcd(int a, int b){
return !b : a ? gcd(b, a % b) ;
}
更相减损术
一种计算 g c d ( a , b ) gcd(a,b) gcd(a,b)的方法
如 a > b a>b a>b,交换 a , b a,b a,b
若 a a a奇 b b b偶则 gcd ( a , b ) = gcd ( a , b / 2 ) \gcd(a,b)=\gcd(a,b/2) gcd(a,b)=gcd(a,b/2)
若 a a a偶 b b b奇则 gcd ( a , b ) = gcd ( a / 2 , b ) \gcd(a,b)=\gcd(a/2,b) gcd(a,b)=gcd(a/2,b)
若 a a a偶 b b b偶则 gcd ( a , b ) = 2 ∗ gcd ( a / 2 , b / 2 ) \gcd(a,b)=2*\gcd(a/2,b/2) gcd(a,b)=2∗gcd(a/2,b/2)
若 a a a奇 b b b奇则 gcd ( a , b ) = gcd ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) gcd(a,b)=gcd(a−b,b)
以上两种算gcd的方法都是 O ( l o g n ) O(logn) O(logn)的
万恶的SD省选出了一道 毒瘤题 SuperGCD,就是a,b很大( 1 0 10000 10^{10000} 1010000),求GCD
用上面的方法,高精需要支持判0,除2,乘2,减
代码有毒就不发了
裴蜀定理: a x + b y = c ax+by=c ax+by=c有解当且仅当 gcd ( a , b ) ∣ c \gcd(a,b)|c gcd(a,b)∣c
扩展欧几里得算法:求ax+by=c的自然数解
推导:
设方程
{ a x 1 + b y 1 = gcd ( a , b ) b x 2 + ( a % b ) y 2 = g c d ( b , a % b ) \begin{cases} ax_1+by_1=\gcd(a,b) \\ bx_2+(a\%b)y_2=gcd(b,a\%b) \end{cases} {ax1+by1=gcd(a,b)bx2+(a%b)y2=gcd(b,a%b)
由 gcd ( a , b ) = gcd ( b , a % b ) \gcd(a,b)=\gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)继续推:
a x 1 + b y 1 = b x 2 + ( a % b ) y 2 = b x 2 + ( a − ⌊ a b ⌋ ∗ b ) y 2 = a y 2 + b ( x 2 − ⌊ a b ⌋ ∗ y 2 ) ax_1+by_1=bx_2+(a\%b)y_2=bx_2+(a-\left\lfloor{\frac{a}{b}}\right\rfloor*b)y_2=ay_2+b(x_2-\left\lfloor{\frac{a}{b}}\right\rfloor*y_2) ax1+by1=bx2+(a%b)y2=bx2+(a−⌊ba⌋∗b)y2=ay2+b(x2−⌊ba⌋∗y2)
所以我们得到
{ x 1 = y 2 y 1 = x 2 − ⌊ a b ⌋ ∗ y 2 \begin{cases} x_1=y_2 \\ y_1=x_2-\left\lfloor{\frac{a}{b}}\right\rfloor*y_2 \end{cases} {x1=y2y1=x2−⌊ba⌋∗y2
很显然, b = 0 , a = gcd ( a , b ) b=0,a=\gcd(a,b) b=0,a=gcd(a,b)时, gcd ( a , b ) x = gcd ( a , b ) \gcd(a,b)x=\gcd(a,b) gcd(a,b)x=gcd(a,b),所以 x = 1 x=1 x=1
于是我们先从原方程递归到b=0,然后从末状态向上回溯,就能够得到方程的一组解
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1, y = 0 ;
return a ;
}
int d = exgcd(b, a % b, y, x) ;
y -= (a / b) * x ;
return d ;
}
a x + b y = c ax+by=c ax+by=c的通解
设 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)为方程 a x + b y = c ax+by=c ax+by=c的一组解
则 ( x 1 + k b gcd ( a , b ) , y 1 − k a gcd ( a , b ) ) (x_1+\frac{kb}{\gcd(a,b)} ,y_1-\frac{ka}{\gcd(a,b)}) (x1+gcd(a,b)kb,y1−gcd(a,b)ka)为方程的通解,其中 k k k为参数
代入方程易知正确性
给一例题 [NOI2002]荒岛野人
将题意转化,我们能够发现其实就是求出最小的 M M M,使得对于任意 i , j i,j i,j
C i + P i ∗ x ≡ C j + P j ∗ x ( m o d M ) C_i+P_i*x≡C_j+P_j*x(mod \ M) Ci+Pi∗x≡Cj+Pj∗x(mod M)的最小正整数解 x x x要么不存在,要么 < m i n ( L i , L j ) <min(L_i,L_j) <min(Li,Lj)
发现M不满足单调性,只能枚举M
将上述同余方程式变形,的到 ( P i − P j ) ∗ x − M ∗ y = C j − C i (P_i-P_j)*x-M*y=C_j-C_i (Pi−Pj)∗x−M∗y=Cj−Ci
用扩展欧几里得去做一下就行了
int n, mx ;
int c[N], p[N], l[N] ;
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b) ;
}
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 ;
}
bool check(int m) {
rep(i, 1, n)
rep(j, i + 1, n) {
int a = p[j] - p[i], b = m, C = c[i] - c[j], x, y, g = gcd(a, b) ;
if (C % g == 0) {
a /= g ;
b /= g ;
C /= g ;
exgcd(a, b, x, y) ;
b = abs(b) ;
x = ((x * C) % b + b) % b ;
if (!x) x += b ;
if (x <= min(l[i], l[j])) return 0 ;
}
}
return 1 ;
}
signed main(){
scanf("%d", &n) ;
rep(i, 1, n) scanf("%d%d%d", &c[i], &p[i], &l[i]), mx = max(mx, c[i]) ;
// 初始洞穴,每年跳多少,寿命
int i = mx ;
while (1) {
if (check(i)) print(i) ;
i++ ;
}
return 0 ;
}
首先,有一些下取整的结论:
结论1: ⌊ A + B ⌋ = A + ⌊ B ⌋ \left\lfloor\ A+B \right\rfloor=A+\left\lfloor\ B\right\rfloor ⌊ A+B⌋=A+⌊ B⌋, A ∈ N A∈\N A∈N, B ∈ R B∈\R B∈R
结论2:当 x ≥ y x≥y x≥y 时,设 x = k y + r x=ky+r x=ky+r,根据结论1易知 ⌊ A x y ⌋ = ⌊ A ( k y + r ) y ⌋ = A k + ⌊ A r y ⌋ = A ∗ ⌊ x y ⌋ + ⌊ A ( x % y ) y ⌋ \left\lfloor\ \frac{Ax}{y}\right\rfloor=\left\lfloor\ \frac{A(ky+r)}{y}\right\rfloor=Ak+\left\lfloor\ \frac{Ar}{y}\right\rfloor=A*\left\lfloor\ \frac{x}{y}\right\rfloor+\left\lfloor\ \frac{A(x\%y)}{y}\right\rfloor ⌊ yAx⌋=⌊ yA(ky+r)⌋=Ak+⌊ yAr⌋=A∗⌊ yx⌋+⌊ yA(x%y)⌋
然后之后我们来说说类欧几里得算法
问题是求下面的三个式子:
φ ( a , b , c , n ) = ∑ i = 0 n ⌊ a i + b c ⌋ \varphi(a,b,c,n)=\sum\limits_{i=0}^n\left\lfloor\ \frac{ai+b}{c} \right\rfloor φ(a,b,c,n)=i=0∑n⌊ cai+b⌋
ψ ( a , b , c , n ) = ∑ i = 0 n ⌊ a i + b c ⌋ 2 \psi(a,b,c,n)=\sum\limits_{i=0}^n\left\lfloor\ \frac{ai+b}{c} \right\rfloor^2 ψ(a,b,c,n)=i=0∑n⌊ cai+b⌋2
ϕ ( a , b , c , n ) = ∑ i = 0 n i ⌊ a i + b c ⌋ \phi(a,b,c,n)=\sum\limits_{i=0}^ni\left\lfloor\ \frac{ai+b}{c} \right\rfloor ϕ(a,b,c,n)=i=0∑ni⌊ cai+b⌋
n ≤ 1 0 9 n≤10^9 n≤109
很显然 φ \varphi φ最简单,我们先试着处理它
暴力肯定不成,数据范围提示我们要写一种 O ( l o g n ) O(logn) O(logn)的方法
设 ξ ( i ) = ⌊ a i + b c ⌋ \xi(i)=\left\lfloor\ \frac{ai+b}{c} \right\rfloor ξ(i)=⌊ cai+b⌋,观察当i增大时, ξ ( i ) \xi(i) ξ(i)是怎么变的
若 a ≥ c a≥c a≥c,则 a ( i + 1 ) c = a i c + a c ≥ a i c + 1 \frac{a(i+1)}{c}=\frac{ai}{c}+\frac{a}{c}≥\frac{ai}{c}+1 ca(i+1)=cai+ca≥cai+1
同理若 b ≥ c b≥c b≥c,显然 b c ≥ 1 \frac{b}{c}≥1 cb≥1
套着下取整符号很烦,我们试图把他拆掉
根据前面提到的结论2,我们能够将 ξ \xi ξ 变形:
ξ ( i ) = ⌊ a i + b c ⌋ = ⌊ ( a % c ) i + ( b % c ) c ⌋ + i ⌊ a c ⌋ + ⌊ b c ⌋ \xi(i)=\left\lfloor\ \frac{ai+b}{c} \right\rfloor=\left\lfloor\ \frac{(a\%c)i+(b\%c)}{c}\right\rfloor+i\left\lfloor\ \frac{a}{c} \right\rfloor+\left\lfloor\ \frac{b}{c} \right\rfloor ξ(i)=⌊ cai+b⌋=⌊ c(a%c)i+(b%c)⌋+i⌊ ca⌋+⌊ cb⌋
则 ∑ i = 0 n ⌊ a i + b c ⌋ = ∑ i = 0 n ( ⌊ ( a % c ) i + ( b % c ) c ⌋ + i ⌊ a c ⌋ + ⌊ b c ⌋ ) \sum\limits_{i=0}^n \left\lfloor\ \frac{ai+b}{c} \right\rfloor=\sum\limits_{i=0}^n (\left\lfloor\ \frac{(a\%c)i+(b\%c)}{c}\right\rfloor+i\left\lfloor\ \frac{a}{c} \right\rfloor+\left\lfloor\ \frac{b}{c} \right\rfloor) i=0∑n⌊ cai+b⌋=i=0∑n(⌊ c(a%c)i+(b%c)⌋+i⌊ ca⌋+⌊ cb⌋)
有没有发现 ∑ i = 0 n ⌊ ( a % c ) i + ( b % c ) c ⌋ \sum\limits_{i=0}^n \left\lfloor\ \frac{(a\%c)i+(b\%c)}{c}\right\rfloor i=0∑n⌊ c(a%c)i+(b%c)⌋也同样是一个一个 φ \varphi φ函数?他对应着 φ ( a % c , b % c , c , n ) \varphi(a\%c, b\%c,c,n) φ(a%c,b%c,c,n)
于是我们可以得到一个很强的结论:
φ ( a , b , c , n ) = φ ( a % c , b % c , c , n ) + n ( n + 1 ) 2 ⌊ a c ⌋ + ( n + 1 ) ⌊ b c ⌋ \varphi(a,b,c,n)=\varphi(a\%c,b\%c,c,n)+\frac{n(n+1)}{2} \left\lfloor\ \frac{a}{c} \right\rfloor + (n+1)\left\lfloor\ \frac{b}{c} \right\rfloor φ(a,b,c,n)=φ(a%c,b%c,c,n)+2n(n+1)⌊ ca⌋+(n+1)⌊ cb⌋
这样我们就把 a , b ≥ c a,b≥c a,b≥c的情况转化成了 a , b < c a,b<c a,b<c
当 a , b < c a,b<c a,b<c 时,显然 ξ ( i ) \xi(i) ξ(i)必定小于 n n n,这样我们可以变换使得上界变为 ξ ( i ) \xi(i) ξ(i),保证从原问题转化到的问题集变小
之后我们发现我们不会做了,考虑该问题的集合意义
a i + b c \frac{ai+b}{c} cai+b 表示在坐标系上其实是一个一次函数(线段),而我们的答案就是该线段以下的整点(坐标为整数)的点的个数
然后按照这样的思路我们重新构造一下 φ \varphi φ
∑ i = 0 n ⌊ a i + b c ⌋ = ∑ i = 0 n ∑ d = 1 ⌊ a n + b c ⌋ [ ⌊ a i + b c ⌋ ≥ d ] \sum\limits_{i=0}^n \left\lfloor\ \frac{ai+b}{c} \right\rfloor = \sum\limits_{i=0}^n \sum\limits_{d=1}^{\left\lfloor\ \frac{an+b}{c} \right\rfloor}[\left\lfloor\ \frac{ai+b}{c} \right\rfloor ≥ d] i=0∑n⌊ cai+b⌋=i=0∑nd=1∑⌊ can+b⌋[⌊ cai+b⌋≥d]
= ∑ i = 0 n ∑ d = 0 ⌊ a n + b c ⌋ − 1 [ c ⌊ a i + b c ⌋ a ≥ c ( d + 1 ) a > ( c d + c − 1 ) a ] =\sum\limits_{i=0}^n \sum\limits_{d=0}^{\left\lfloor\ \frac{an+b}{c} \right\rfloor-1}[ \frac{c \left\lfloor \frac{ai+b}{c}\right\rfloor}{a} ≥ \frac{c(d+1)}{a} > \frac{(cd+c-1)}{a}] =i=0∑nd=0∑⌊ can+b⌋−1[ac⌊cai+b⌋≥ac(d+1)>a(cd+c−1)]
= ∑ i = 0 n ∑ d = 0 ⌊ a n + b c ⌋ − 1 [ i > c d + c − b − 1 a ] =\sum\limits_{i=0}^n \sum\limits_{d=0}^{\left\lfloor\ \frac{an+b}{c} \right\rfloor-1}[i>\frac{cd+c-b-1}{a}] =i=0∑nd=0∑⌊ can+b⌋−1[i>acd+c−b−1]
后面[]中的元素其实就是统计大于 c d + c − b − 1 a \frac{cd+c-b-1}{a} acd+c−b−1的i的个数,其恰好看做 n − ⌊ c d + c − b − 1 a ⌋ n-\left\lfloor \frac{cd+c-b-1}{a} \right\rfloor n−⌊acd+c−b−1⌋(好巧),因此不难看出我们可以吧原式华为与i无关的和式:
原式 = ∑ d = 0 ⌊ a n + b c ⌋ − 1 n − ⌊ c d + c − b − 1 a ⌋ = \sum\limits_{d=0}^{\left\lfloor\ \frac{an+b}{c}\right\rfloor-1} n-\left\lfloor \frac{cd+c-b-1}{a} \right\rfloor =d=0∑⌊ can+b⌋−1n−⌊acd+c−b−1⌋
= n ⌊ a n + b c ⌋ − ∑ d = 0 ⌊ a n + b c ⌋ − 1 ⌊ c d + c − b − 1 a ⌋ = n\left\lfloor \frac{an+b}{c} \right\rfloor - \sum\limits_{d=0}^{\left\lfloor\ \frac{an+b}{c}\right\rfloor-1} \left\lfloor \frac{cd+c-b-1}{a} \right\rfloor =n⌊can+b⌋−d=0∑⌊ can+b⌋−1⌊acd+c−b−1⌋
= n ⌊ a n + b c ⌋ − φ ( c , c − b − 1 , a , ⌊ a n + b c ⌋ − 1 ) =n\left\lfloor \frac{an+b}{c} \right\rfloor - \varphi(c,c-b-1,a,\left\lfloor \frac{an+b}{c} \right\rfloor-1) =n⌊can+b⌋−φ(c,c−b−1,a,⌊can+b⌋−1)
因此,我们推出来了 φ ( a , b , c , n ) = φ ( c , c − b − 1 , a , ξ ( n ) − 1 ) \varphi(a,b,c,n)=\varphi(c,c-b-1,a,\xi(n)-1) φ(a,b,c,n)=φ(c,c−b−1,a,ξ(n)−1)
通过上式,我们能够在 O ( l o g a ) O(loga) O(loga)内计算出 φ \varphi φ的值(因为其计算的本质是 gcd \gcd gcd,故时间复杂度也相同)
当然边界为 a = 0 a=0 a=0没话说
放一小段程序:
ll f(ll a, ll b, ll c, ll n) {
if (!a) return (n + 1) * (b / c) % MOD ;
if (a >= c || b >= c) return (f(a % c, b % c, c, n) + (a / c) * n % MOD * (n + 1) % MOD * inv2 % MOD + (b / c) * (n + 1) % MOD) % MOD ;
ll m = (a * n + b) / c ;
return (n * m % MOD - f(c, c - b - 1, a, m - 1)) % MOD ;
}
之后考虑 ψ \psi ψ,根据上一题的研究方法,我们肯定也是先研究 a , b ≥ c a,b \ge c a,b≥c的情况
通过 φ \varphi φ的结论我们能够对 ψ \psi ψ做第一步变换:
ψ ( a , b , c , n ) = ∑ i = 0 n ( ⌊ ( ( a % c ) i + ( b % c ) c ⌋ + i ⌊ a c ⌋ + ⌊ b c ⌋ ) 2 \psi(a,b,c,n)=\sum\limits_{i=0}^n(\lfloor \frac{((a\%c)i+(b\%c)}{c} \rfloor+i\lfloor \frac{a}{c}\rfloor+\lfloor \frac{b}{c} \rfloor)^2 ψ(a,b,c,n)=i=0∑n(⌊c((a%c)i+(b%c)⌋+i⌊ca⌋+⌊cb⌋)2
= ∑ i = 0 n ( i 2 ⌊ a c ⌋ + ⌊ b c ⌋ 2 + ⌊ ( a % c ) i + ( b % c ) c ⌋ + 2 i ⌊ a c ⌋ ⌊ ( a % c ) i + ( b % c ) c ⌋ + 2 ⌊ b c ⌋ ⌊ ( a % c ) i + ( b % c ) c ⌋ + 2 i ⌊ a c ⌋ ⌊ b c ⌋ ) =\sum\limits_{i=0}^n(i^2\lfloor \frac{a}{c} \rfloor+\lfloor \frac{b}{c} \rfloor^2+\lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor+2i\lfloor \frac{a}{c} \rfloor\lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor+2\lfloor \frac{b}{c} \rfloor \lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor+2i\lfloor \frac{a}{c} \rfloor\lfloor \frac{b}{c} \rfloor) =i=0∑n(i2⌊ca⌋+⌊cb⌋2+⌊c(a%c)i+(b%c)⌋+2i⌊ca⌋⌊c(a%c)i+(b%c)⌋+2⌊cb⌋⌊c(a%c)i+(b%c)⌋+2i⌊ca⌋⌊cb⌋)
观察式子,哪些是我们已经可以求得的
我们发现 i 2 i^2 i2可以通过公式直接求, ⌊ ( a % c ) i + ( b % c ) c ⌋ \lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor ⌊c(a%c)i+(b%c)⌋显然就是 φ ( a % c , b % c , c , n ) \varphi(a \%c,b\%c,c,n) φ(a%c,b%c,c,n), ⌊ ( a % c ) i + ( b % c ) c ⌋ 2 \lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor^2 ⌊c(a%c)i+(b%c)⌋2是 ψ ( a % c , b % c , c , n ) \psi(a \%c,b\%c,c,n) ψ(a%c,b%c,c,n)
那么 i ⌊ ( a % c ) i + ( b % c ) c ⌋ i\lfloor \frac{(a\%c)i+(b\%c)}{c} \rfloor i⌊c(a%c)i+(b%c)⌋怎么求? 他实际就是 ϕ ( a % c , b % c , c , n ) \phi(a \%c,b\%c,c,n) ϕ(a%c,b%c,c,n)
既然要求出 ψ \psi ψ需要用到 ϕ \phi ϕ,那么我们就赶紧对 ϕ \phi ϕ做一些处理
令 S k ( n ) = ∑ i = 1 n i k S_k(n)=\sum\limits_{i=1}^ni^k Sk(n)=i=1∑nik,则可以吧求和符号消去:
ψ ( a , b , c , n ) = ψ ( a % c , b % c , c , n ) + ⌊ a c ⌋ 2 S 2 ( n ) + ( n + 1 ) ⌊ b c ⌋ 2 + 2 ⌊ a c ⌋ ϕ ( a % c , b % c , c , n ) + 2 ⌊ b c ⌋ ψ ( a % c , b % c , c , n ) + 2 ⌊ a c ⌋ ⌊ b c ⌋ S 1 ( n ) \psi(a,b,c,n)=\psi(a\%c,b\%c,c,n)+\lfloor \frac{a}{c}\rfloor^2S_2(n)+(n+1)\lfloor \frac{b}{c}\rfloor^2+2\lfloor \frac{a}{c}\rfloor\phi(a\%c,b\%c,c,n)+2\lfloor \frac{b}{c}\rfloor\psi(a\%c,b\%c,c,n)+2\lfloor \frac{a}{c}\rfloor\lfloor \frac{b}{c}\rfloor S_1(n) ψ(a,b,c,n)=ψ(a%c,b%c,c,n)+⌊ca⌋2S2(n)+(n+1)⌊cb⌋2+2⌊ca⌋ϕ(a%c,b%c,c,n)+2⌊cb⌋ψ(a%c,b%c,c,n)+2⌊ca⌋⌊cb⌋S1(n)
ψ ( a , b , c , n ) = ∑ i = 0 n ∑ d = 1 ⌊ a n + b c ⌋ 2 [ ⌊ a i + b c ⌋ 2 ≥ d ] \psi(a,b,c,n)=\sum\limits_{i=0}^n\sum\limits_{d=1}^{\lfloor \frac{an+b}{c}\rfloor^2}[\lfloor \frac{ai+b}{c}\rfloor^2 \ge d] ψ(a,b,c,n)=i=0∑nd=1∑⌊can+b⌋2[⌊cai+b⌋2≥d]
注意到这个式不能计算,原因是只保证 ξ ( n ) ≤ n \xi(n) \le n ξ(n)≤n,但是 x i ( n ) 2 xi(n)^2 xi(n)2就可能是 n 2 n^2 n2级别的,我们要是用一些小技巧
显然通过等差数列 X 2 = − X + 2 ∑ i = 1 x i X^2=-X+2\sum_{i=1}^xi X2=−X+2∑i=1xi
那么上述式子等价于
∑ i = 0 n 2 ∑ d = 1 ⌊ a i + b c ⌋ d − ⌊ a i + b c ⌋ \sum\limits_{i=0}^n2\sum\limits_{d=1}^{\lfloor \frac{ai+b}{c}\rfloor}d-\lfloor \frac{ai+b}{c}\rfloor i=0∑n2d=1∑⌊cai+b⌋d−⌊cai+b⌋
= 2 ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) ∑ i = 0 n [ a i + b c ≥ d + 1 ] − ⌊ a i + b c ⌋ =2\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)\sum\limits_{i=0}^n[\frac{ai+b}{c} \ge d+1]-\lfloor \frac{ai+b}{c}\rfloor =2d=0∑⌊can+b⌋−1(d+1)i=0∑n[cai+b≥d+1]−⌊cai+b⌋
= 2 ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) ∑ i = 0 n [ i > c d + c − b − 1 a ] − φ ( a , b , c , n ) =2\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)\sum\limits{i=0}^n[i>\frac{cd+c-b-1}{a}]-\varphi(a,b,c,n) =2d=0∑⌊can+b⌋−1(d+1)∑i=0n[i>acd+c−b−1]−φ(a,b,c,n)
= 2 ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) ( n − ⌊ c d + c − b − 1 a ⌋ ) − φ ( a , b , c , n ) =2\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)(n-\lfloor \frac{cd+c-b-1}{a}\rfloor)-\varphi(a,b,c,n) =2d=0∑⌊can+b⌋−1(d+1)(n−⌊acd+c−b−1⌋)−φ(a,b,c,n)
= 2 ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) ( n − ⌊ c d + c − b − 1 a ⌋ ) − φ ( a , b , c , n ) =2\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)(n-\lfloor \frac{cd+c-b-1}{a}\rfloor)-\varphi(a,b,c,n) =2d=0∑⌊can+b⌋−1(d+1)(n−⌊acd+c−b−1⌋)−φ(a,b,c,n)
= 2 n ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) − 2 ∑ d = 0 ⌊ a n + b c ⌋ − 1 ( d + 1 ) [ c d + c − b − 1 a ] − φ ( a , b , c , n ) =2n\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)-2\sum\limits_{d=0}^{\lfloor \frac{an+b}{c}\rfloor-1}(d+1)[\frac{cd+c-b-1}{a}]-\varphi(a,b,c,n) =2nd=0∑⌊can+b⌋−1(d+1)−2d=0∑⌊can+b⌋−1(d+1)[acd+c−b−1]−φ(a,b,c,n)
= n ξ ( n ) ( ξ ( n ) + 1 ) − 2 ϕ ( c , c − b − 1 , a , ξ ( n ) − 1 ) − 2 φ ( c , c − b − 1 , a , ξ ( n ) − 1 ) − φ ( a , b , c , n ) =n\xi(n)(\xi(n)+1)-2\phi(c,c-b-1,a,\xi(n)-1)-2\varphi(c,c-b-1,a,\xi(n)-1)-\varphi(a,b,c,n) =nξ(n)(ξ(n)+1)−2ϕ(c,c−b−1,a,ξ(n)−1)−2φ(c,c−b−1,a,ξ(n)−1)−φ(a,b,c,n)
通过上述推导,我们就把 ψ \psi ψ成功转化成了 ϕ \phi ϕ,并且 n n n的规模减小了
φ ( a , b , c , n ) = n ξ ( n ) ( ξ ( n ) + 1 ) − 2 ϕ ( c , c − b − 1 , a , ξ ( n ) − 1 ) − 2 φ ( c , c − b − 1 , a , ξ ( n ) − 1 ) − φ ( a , b , c , n ) \varphi(a,b,c,n)=n\xi(n)(\xi(n)+1)-2\phi(c,c-b-1,a,\xi(n)-1)-2\varphi(c,c-b-1,a,\xi(n)-1)-\varphi(a,b,c,n) φ(a,b,c,n)=nξ(n)(ξ(n)+1)−2ϕ(c,c−b−1,a,ξ(n)−1)−2φ(c,c−b−1,a,ξ(n)−1)−φ(a,b,c,n)
最后,我们只需求出 ϕ \phi ϕ即可,非常简单,按照惯例,我满依然将 a , b ≥ c a,b \ge c a,b≥c的情形进行转换。我们直接推出结论:
ϕ ( a , b , c , n ) = ⌊ a c ⌋ S 2 ( n ) + ⌊ b c ⌋ S 1 ( n ) + ϕ ( a % c , b % c , c , n ) \phi(a,b,c,n)=\lfloor \frac{a}{c}\rfloor S_2(n)+\lfloor \frac{b}{c}\rfloor S_1(n)+\phi(a\%c,b\%c,c,n) ϕ(a,b,c,n)=⌊ca⌋S2(n)+⌊cb⌋S1(n)+ϕ(a%c,b%c,c,n)
a , b < c a,b < c a,b<c的情况也类似,用 ξ \xi ξ 替代原式,这里同样十分简单,过程与上面相同,
ϕ ( a , b , c , n ) = 2 ξ ( n ) S 1 ( n ) − φ ( c , c − b − 1 , a , ξ ( n ) − 1 ) − ψ ( c , c − b − 1 , a , ξ ( n ) − 1 ) 2 \phi(a,b,c,n)=\frac{2\xi(n)S_1(n)-\varphi(c,c-b-1,a,\xi(n)-1)-\psi(c,c-b-1,a,\xi(n)-1)}{2} ϕ(a,b,c,n)=22ξ(n)S1(n)−φ(c,c−b−1,a,ξ(n)−1)−ψ(c,c−b−1,a,ξ(n)−1)
通过上述方式我们即可求解上述三式
这是个表
我们知道 ∑ i = 1 n C i k = C n + 1 k + 1 \sum\limits_{i=1}^nC_i^k=C_{n+1}^{k+1} i=1∑nCik=Cn+1k+1
∑ i = 1 n i 2 = ∑ i = 1 n i ( i − 1 ) + i = 2 ∗ ∑ i = 1 n C i 2 + ∑ i = 1 n C i 1 = 2 C n + 1 3 + C n + 1 2 = n ∗ ( n + 1 ) ∗ ( 2 n + 1 ) 6 \sum\limits_{i=1}^ni^2=\sum\limits_{i=1}^ni(i-1)+i=2*\sum\limits_{i=1}^nC_i^2+\sum\limits_{i=1}^nC_i^1=2C_{n+1}^3+C_{n+1}^2=\frac{n*(n+1)*(2n+1)}{6} i=1∑ni2=i=1∑ni(i−1)+i=2∗i=1∑nCi2+i=1∑nCi1=2Cn+13+Cn+12=6n∗(n+1)∗(2n+1)
因为模不支持除法,为此,我们引入乘法逆元来解决问题
对于正整数 a a a和 m m m,如果 a x ≡ 1 ( m o d m ) ax≡1(mod \ m) ax≡1(mod m),则 x x x的最小整整数解为 a a a模 m m m意义下的逆元,记做 a − 1 a^{-1} a−1
求解逆元有3种方法
第一种:费马小定理
费马小定理: a p − 1 ≡ 1 ( m o d p ) a^{p-1}≡1(mod \ p) ap−1≡1(mod p),其中必须保证p为质数
所以 a ∗ a p − 2 ≡ 1 ( m o d p ) a*a^{p-2}≡1(mod \ p) a∗ap−2≡1(mod p),即 a p − 2 a^{p-2} ap−2即为逆元
int getinv(int a, int p) { // inv = a ^ (p - 2)
return power(a, p - 2, p) ; // 调用快速幂
}
第二种:扩展欧几里得
根据逆元定义可以转化成丢番图方程 a x + p y = 1 ax+py=1 ax+py=1
然后解这个方程即可
当 gcd ( a , p ) ≠ 1 \gcd(a,p)≠1 gcd(a,p)̸=1时,方程无解
这告诉我们,存在逆元的前提是 gcd ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1
int getinv(int a, int p) { // 可以求出单个inv
ll x, y ;
ll d = exgcd(a, p, x, y) ;
return d == 1 ? (x + p) % p ? -1 ;
}
第三种:线性递推
a − 1 = − ⌊ m a ⌋ ∗ ( m % a ) − 1 a^{-1}=-\left\lfloor\ \frac{m}{a}\right\rfloor*(m\%a)^{-1} a−1=−⌊ am⌋∗(m%a)−1
证明:设 m = k a + r ( r < a ) m=ka+r(r<a) m=ka+r(r<a),则 k = ⌊ m a ⌋ k=\left\lfloor \frac{m}{a}\right\rfloor k=⌊am⌋且 r = m % a r=m\%a r=m%a
因为 k a + r ≡ 0 ( m o d m ) ka+r≡0(mod \ m) ka+r≡0(mod m),所以两边同时乘以 a − 1 r − 1 a^{-1}r^{-1} a−1r−1得:
k r − 1 + a − 1 ≡ 0 ( m o d m ) kr^{-1}+a^{-1}≡0(mod \ m) kr−1+a−1≡0(mod m)
a − 1 ≡ − k r − 1 ≡ − ⌊ m a ⌋ ∗ ( m % a ) ( m o d m ) a^{-1}≡-kr^{-1}≡-\left\lfloor\ \frac{m}{a}\right\rfloor*(m\%a)(mod \ m) a−1≡−kr−1≡−⌊ am⌋∗(m%a)(mod m)
时间复杂度 O ( n ) O(n) O(n),非常优秀
void initinv(int n, int p) {
inv[1] = 1 ;
for (int i = 2; i <= n; i++) inv[i] = (ll) (p - p / i) * inv[p % i] % p ;
}
给定 n n n个同余方程( m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn两两互质)
{ 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≡a_1(mod \ m_1) \\ x≡a_2(mod \ m_2) \\ .... \\ x≡a_n(mod \ m_n) \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1(mod m1)x≡a2(mod m2)....x≡an(mod mn)
令 M = ∏ i = 1 n m i M=\prod\limits_{i=1}^nm_i M=i=1∏nmi,则满足上述方程的 x x x的值为 x = ∑ i = 1 n a i M m i M m i − 1 x=\sum\limits_{i=1}^na_i\frac{M}{m_i}\frac{M}{m_i}^{-1} x=i=1∑naimiMmiM−1,其中 M m i − 1 \frac{M}{m_i}^{-1} miM−1表示 M m i \frac{M}{m_i} miM在模 m i m_i mi意义下的乘法逆元
代入显然正确
互质模板题 [TJOI2009]猜数字
CRT的题目都尽量用龟速乘吧,防止爆longlong
板子直接上
int n ;
ll a[N], b[N], r[N], m[N] ;
ll x, y ;
void exgcd(ll a, ll b, ll &x, ll &y) { // exgcd解出逆元
if (!b) {
x = 1 ; y = 0 ;
return ;
}
exgcd(b, a % b, y, x) ;
y -= (a / b) * x ;
}
ll mul(ll a, ll b, ll MOD) { // 最后一个点爆long long 要用龟速乘
ll ans = 0 ;
for(; b; b >>= 1, a = (a + a) % MOD) if (b & 1) ans = (ans + a) % MOD ;
return ans ;
}
void china() {
ll sum = 1, ans = 0 ;
rep(i, 1, n) sum *= b[i] ; // 求lcm
rep(i, 1, n) m[i] = sum / b[i] ; // 除一下
rep(i, 1, n) {
exgcd(m[i], b[i], x, y) ;
r[i] = (x % b[i] + b[i]) % b[i] ;
// r[i]为m[i]的逆元,(r[i]=x)*m[i]≡1(% b[i]) -> r[i]*m[i]+b[i]*y=1
}
rep(i, 1, n) ans= (ans + mul(mul(a[i], m[i], sum), r[i], sum)) % sum ; // ans = Σ a[i]*m[i]*r[i]
if (ans < 0) ans += sum ;
printf("%lld\n", ans) ;
}
signed main(){
scanf("%d", &n) ;
rep(i, 1, n) scanf("%lld", &a[i]) ;
rep(i, 1, n) scanf("%lld", &b[i]) ;
china() ;
return 0 ;
}
那如果模数不是两两互质的呢?
发现上述式子失效,只能另辟蹊径
设目前解除前 k − 1 k-1 k−1个方程的解为 x x x
M = L C M i = 1 k − 1 m i M=LCM_{i=1}^{k-1}m_i M=LCMi=1k−1mi
前 k − 1 k-1 k−1个方程的通解 x + i ∗ M ( i ∈ Z ) x+i*M(i∈\Z) x+i∗M(i∈Z)
那么对于加入的第k个方程
我们要求出一个 t t t,使得 x + t ∗ M = a k ( m o d m k ) x+t*M=a_k(mod \ m_k) x+t∗M=ak(mod mk)
转化一下得到 t ∗ M = a k − x ( m o d m k ) t*M=a_k-x(mod \ m_k) t∗M=ak−x(mod mk)
对这个式子做exgcd就能够求出 t t t
若同余式无解,则方程组无解
否则前 k k k个方程的解 x k = x + t ∗ M x_k=x+t*M xk=x+t∗M
相当于做k次扩欧求
int n ;
ll A[N], B[N] ;
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 mul(ll a, ll b, ll MOD) {
ll res = 0 ;
for (; b; b >>= 1, a = (ll)(a + a) % MOD) if (b & 1) res = (res + a) % MOD ;
return res ;
}
ll exchina() {
ll x, y, M = B[1], ans = A[1] ; // 一般特判第一条式子
rep(i, 2, n) {
ll a = M, b = B[i], c = (A[i] - ans % b + b) % b ;
ll gcd = exgcd(a, b, x, y), nw = b / gcd ;
// x * M(a) + y * B[i](b) = gcd(a,b) --> (A[i]-ans)
if (c % gcd) return -1 ; // gcd|c,否则无解
x = mul(x, c / gcd, nw) ; // x * ((A[i]-ans) / gcd)
ans += x * M ; // ans += x * M
M *= nw ; // 更新LCM
ans = (ans % M + M) % M ; // 总的模数为M,模一下
}
return (ans % M + M) % M ;
}
signed main(){
while (scanf("%d", &n) != EOF) {
rep(i, 1, n) scanf("%lld%lld", &B[i], &A[i]) ;
printf("%lld\n", exchina()) ;
}
return 0 ;
}