【学习笔记】类欧几里得

280 篇文章 1 订阅

如果学过数学,可以从 3.类欧几里得 开始看。

1.概述

用于解决有关等差数列每一项的除法下取整的值。具体来说,有三种。

f ( a , b , c , n ) = ∑ x = 0 n − 1 ⌊ a x + b c ⌋ f(a,b,c,n)=\sum_{x=0}^{n-1}\left\lfloor\frac{ax+b}{c}\right\rfloor f(a,b,c,n)=x=0n1cax+b

g ( a , b , c , n ) = ∑ x = 0 n − 1 ⌊ a x + b c ⌋ ⋅ x g(a,b,c,n)=\sum_{x=0}^{n-1}\left\lfloor\frac{ax+b}{c}\right\rfloor\cdot x g(a,b,c,n)=x=0n1cax+bx

h ( a , b , c , n ) = ∑ x = 0 n − 1 ⌊ a x + b c ⌋ 2 h(a,b,c,n)=\sum_{x=0}^{n-1}\left\lfloor\frac{ax+b}{c}\right\rfloor^2 h(a,b,c,n)=x=0n1cax+b2

2.数学定理

如果没有特殊说明,认为所有未知数为整数。

2.0.拐弯抹角

a = m c + r    ( 0 ≤ r < c ) ⇔ m = ⌊ a c ⌋ ,    r = a   m o d   c a=mc+r\;(0\le r<c)\\ \Leftrightarrow m=\left\lfloor\frac{a}{c}\right\rfloor,\;r=a\bmod c a=mc+r(0r<c)m=ca,r=amodc

类似地,我们有
a = m c + r    ( − c < r ≤ 0 ) ⇔ m = ⌈ a c ⌉ \begin{aligned} a&=mc+r\;(-c<r\le 0)\\ \Leftrightarrow m&=\left\lceil\frac{a}{c}\right\rceil \end{aligned} am=mc+r(c<r0)=ca

在后面的叙述中,该定理在被使用之前,可能不会明确指出。

2.1.上下不安

此成语读作shàng xià bù ān

⌊ a c ⌋ = ⌈ a − ( c − 1 ) c ⌉ \left\lfloor\frac{a}{c}\right\rfloor=\left\lceil\frac{a-(c-1)}{c}\right\rceil ca=ca(c1)

也即, ⌊ a + ( c − 1 ) c ⌋ = ⌈ a c ⌉ \left\lfloor\frac{a+(c-1)}{c}\right\rfloor=\left\lceil\frac{a}{c}\right\rceil ca+(c1)=ca

证明非常简单。不妨设 a = m c + r    ( 0 ≤ r < c ) a=mc+r\;(0\le r < c) a=mc+r(0r<c),此时 m = ⌊ a c ⌋ m=\left\lfloor\frac{a}{c}\right\rfloor m=ca

r ′ = r − ( c − 1 ) r'=r-(c-1) r=r(c1),可知 a − ( c − 1 ) = m c + r ′    ( − c < r ′ ≤ 0 ) a-(c-1)=mc+r'\;(-c<r'\le 0) a(c1)=mc+r(c<r0),得 m = ⌈ a − ( c − 1 ) c ⌉ m=\left\lceil\frac{a-(c-1)}{c}\right\rceil m=ca(c1)

所以第一个等式成立。第二个等式与第一个等式是等价的。

2.2.整数分离

∀ x ∈ R ,    ⌊ x + k ⌋ = ⌊ x ⌋ + k \forall x\in\R,\;\left\lfloor x+k\right\rfloor=\left\lfloor x\right\rfloor+k xR,x+k=x+k

正确性是显然的。

2.3.乘积分离

⌊ a x c ⌋ = ⌊ ( a   m o d   c ) ⋅ x c ⌋ + ⌊ a c ⌋ ⋅ x \left\lfloor\frac{ax}{c}\right\rfloor=\left\lfloor\frac{(a\bmod c)\cdot x}{c}\right\rfloor+\left\lfloor\frac{a}{c}\right\rfloor\cdot x cax=c(amodc)x+cax

其实就是 2.2.整数分离 的应用。设 a = m c + r    ( 0 ≤ r < c ) a=mc+r\;(0\le r < c) a=mc+r(0r<c),则 ⌊ a x c ⌋ = ⌊ ( m c + r ) x c ⌋ = ⌊ m x + r x c ⌋ = m x + ⌊ r x c ⌋ \left\lfloor\frac{ax}{c}\right\rfloor=\left\lfloor\frac{(mc+r)x}{c}\right\rfloor=\left\lfloor mx+\frac{rx}{c}\right\rfloor=mx+\left\lfloor\frac{rx}{c}\right\rfloor cax=c(mc+r)x=mx+crx=mx+crx

我们又知道 m = ⌊ a c ⌋ ,    r = a   m o d   c m=\left\lfloor\frac{a}{c}\right\rfloor,\;r=a\bmod c m=ca,r=amodc,替换即可。

2.4.误差范围

∀ x ∈ R ,    a ≤ x ⇔ a ≤ ⌊ x ⌋ \forall x\in\R,\;a\le x\Leftrightarrow a\le\left\lfloor x\right\rfloor xR,axax

类似地,我们有
∀ x ∈ R ,    a ≥ x ⇔ a ≥ ⌈ x ⌉ \forall x\in\R,\;a\ge x\Leftrightarrow a\ge\lceil x\rceil xR,axax

正确性是显然的:只需要证明 a a a 合法的取值既没有变少,也没有变多即可。

2.5.布尔计算

∑ j = 1 n [ j ≤ a ] = ∑ j = 0 n − 1 [ j < a ] = min ⁡ ( n , a ) \sum_{j=1}^{n}[j\le a]=\sum_{j=0}^{n-1}[j<a]=\min(n,a) j=1n[ja]=j=0n1[j<a]=min(n,a)

3.类欧几里得

3.1.求 f f f

别忘了 f f f 的定义,
f ( a , b , c , n ) = ∑ x = 0 n − 1 ⌊ a x + b c ⌋ f(a,b,c,n)=\sum_{x=0}^{n-1}\left\lfloor\frac{ax+b}{c}\right\rfloor f(a,b,c,n)=x=0n1cax+b

很明显,这是最简单的一个。并且它会是 g g g h h h 的基础。

3.1.0.规定

认为 a > 0 a>0 a>0,因为在其他情况下:

  • a = 0 a=0 a=0 时,显然可直接得到 f ( a , b , c , n ) = n ⌊ b c ⌋ f(a,b,c,n)=n\left\lfloor\frac{b}{c}\right\rfloor f(a,b,c,n)=ncb
  • a < 0 a<0 a<0 时,根据其本质,我们知道 f ( a , b , c , n ) = f [ − a , ( n − 1 ) a + b , c , n ] f(a,b,c,n)=f[-a,(n-1)a+b,c,n] f(a,b,c,n)=f[a,(n1)a+b,c,n]

3.1.1.情况一

a ≥ c a\ge c ac 或者 b ≥ c b\ge c bc 时,根据 2.3.乘积分离 (顺便在 b b b 身上使用 2.2.整数分离),我们可以发现,

f ( a , b , c , n ) = ∑ x = 0 n − 1 [ ⌊ ( a   m o d   c ) x + ( b   m o d   c ) c ⌋ + x ⌊ a c ⌋ + ⌊ b c ⌋ ] = f ( a   m o d   c , b   m o d   c , c , n ) + n ( n − 1 ) 2 ⌊ a c ⌋ + n ⌊ b c ⌋ \begin{aligned} f(a,b,c,n)&=\sum_{x=0}^{n-1}\left[\left\lfloor\frac{(a\bmod c)x+(b\bmod c)}{c}\right\rfloor+x\left\lfloor\frac{a}{c}\right\rfloor+\left\lfloor\frac{b}{c}\right\rfloor\right]\\ &=f(a\bmod c,b\bmod c,c,n)+\frac{n(n-1)}{2}\left\lfloor\frac{a}{c}\right\rfloor+n\left\lfloor\frac{b}{c}\right\rfloor \end{aligned} f(a,b,c,n)=x=0n1[c(amodc)x+(bmodc)+xca+cb]=f(amodc,bmodc,c,n)+2n(n1)ca+ncb

3.1.2.情况二

0 < a < c 0<a<c 0<a<c 并且 b < c b<c b<c 时,令
m = ⌊ ( n − 1 ) a + b c ⌋ m=\left\lfloor\frac{(n-1)a+b}{c}\right\rfloor m=c(n1)a+b

(顺便叨叨一句,这个 m m m 在后面会很常见,都是这个定义。)

显然 min ⁡ ( ⌊ a x + b c ⌋ , m ) = ⌊ a x + b c ⌋ \min(\left\lfloor\frac{ax+b}{c}\right\rfloor,m)=\left\lfloor\frac{ax+b}{c}\right\rfloor min(cax+b,m)=cax+b 总成立。利用 2.5.布尔计算2.4.误差范围2.0.拐弯抹角,可以知道

f ( a , b , c , n ) = ∑ x = 0 n − 1 ∑ j = 0 m − 1 [ j + 1 ≤ ⌊ a x + b c ⌋ ] = ∑ x = 0 n − 1 ∑ j = 0 m − 1 [ c j + c ≤ a x + b ] = ∑ j = 0 m − 1 ∑ x = 0 n − 1 [ a x ≥ c j + c − b ] = ∑ j = 0 m − 1 ∑ x = 0 n − 1 [ x ≥ ⌈ c j + c − b a ⌉ ] = ∑ j = 0 m − 1 ∑ x = 0 n − 1 [ x ≥ ⌊ c j + c − b + a − 1 a ⌋ ] \begin{aligned} f(a,b,c,n)&=\sum_{x=0}^{n-1}\sum_{j=0}^{m-1}\left[j+1\le\left\lfloor\frac{ax+b}{c}\right\rfloor\right]\\ &=\sum_{x=0}^{n-1}\sum_{j=0}^{m-1}\left[cj+c\le ax+b\right]\\ &=\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}\left[ax\ge cj+c-b\right]\\ &=\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}\left[x\ge\left\lceil\frac{cj+c-b}{a}\right\rceil\right]\\ &=\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}\left[x\ge\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right] \end{aligned} f(a,b,c,n)=x=0n1j=0m1[j+1cax+b]=x=0n1j=0m1[cj+cax+b]=j=0m1x=0n1[axcj+cb]=j=0m1x=0n1[xacj+cb]=j=0m1x=0n1[xacj+cb+a1]

这很难计算。我们利用容斥,对于每一个 j j j,计算有多少个 x x x 是不满足此条件的。然后就可以利用 2.5.布尔计算 了。于是乎……

f ( a , b , c , n ) = ∑ j = 0 m − 1 ∑ x = 0 n − 1 [ x ≥ ⌊ c j + c − b + a − 1 a ⌋ ] = n m − ∑ j = 0 m − 1 ∑ x = 0 n − 1 [ x < ⌊ c j + c − b + a − 1 a ⌋ ] = n m − ∑ j = 0 m − 1 min ⁡ ( n , ⌊ c j + c − b + a − 1 a ⌋ ) \begin{aligned} f(a,b,c,n)&=\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}\left[x\ge\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right]\\ &=nm-\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}\left[x<\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right]\\ &=nm-\sum_{j=0}^{m-1}\min\left(n,\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right) \end{aligned} f(a,b,c,n)=j=0m1x=0n1[xacj+cb+a1]=nmj=0m1x=0n1[x<acj+cb+a1]=nmj=0m1min(n,acj+cb+a1)

显然,在 j j j 最大时(即 j j j m − 1 m-1 m1 时),其最大值
max ⁡ ( ⌊ c j + c − b + a − 1 a ⌋ ) ≤ ⌊ n a − 1 a ⌋ = n − 1 \max\left(\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right)\le\left\lfloor\frac{na-1}{a}\right\rfloor=n-1 max(acj+cb+a1)ana1=n1

即: ⌊ c j + c − b + a − 1 a ⌋ < n \left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor<n acj+cb+a1<n 恒成立(该不等式在以后的叙述中也十分有用)。

所以

f ( a , b , c , n ) = n m − ∑ j = 0 m − 1 ⌊ c j + c − b + a − 1 a ⌋ = n m − f ( c , c − b + a − 1 , a , m ) \begin{aligned} f(a,b,c,n)&=nm-\sum_{j=0}^{m-1}\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\\ &=nm-f(c,c-b+a-1,a,m) \end{aligned} f(a,b,c,n)=nmj=0m1acj+cb+a1=nmf(c,cb+a1,a,m)

3.1.3.总结

请注意公差 a a a 与除数 c c c 的变化。在 3.1.1.情况一 中, a ′ = a   m o d   c a'=a\bmod c a=amodc ;在 3.1.2.情况二 中, a ′ = c ,    c ′ = a a'=c,\;c'=a a=c,c=a 。这跟欧几里得(辗转相除)求最大公约数是相似的。所以得名。

也可以看出,时间复杂度是 O [ log ⁡ ( a + c ) ] \mathcal O[\log(a+c)] O[log(a+c)] 的。

3.2.求 g g g

写一下, g g g 的定义是
g ( a , b , c , n ) = ∑ x = 0 n − 1 x ⌊ a x + b c ⌋ g(a,b,c,n)=\sum_{x=0}^{n-1}x\left\lfloor\frac{ax+b}{c}\right\rfloor g(a,b,c,n)=x=0n1xcax+b

由于式子的推导在 f f f 中已经进行了很多,一些地方将会沿用 f f f 中的结论。

3.2.1.情况一

a ≥ c a\ge c ac 或者 b ≥ c b\ge c bc 时,

g ( a , b , c , n ) = n ( n − 1 ) ( 2 n − 1 ) 6 ⌊ a c ⌋ + n ( n − 1 ) 2 ⌊ b c ⌋ + g ( a   m o d   c , b   m o d   c , c , n ) \begin{aligned} g(a,b,c,n)&=\frac{n(n-1)(2n-1)}{6}\left\lfloor\frac{a}{c}\right\rfloor\\ &+\frac{n(n-1)}{2}\left\lfloor\frac{b}{c}\right\rfloor\\ &+g(a\bmod c,b\bmod c,c,n) \end{aligned} g(a,b,c,n)=6n(n1)(2n1)ca+2n(n1)cb+g(amodc,bmodc,c,n)

这里用到了平方和公式。基本方法还是利用 a = c ⌊ a c ⌋ + ( a   m o d   c ) a=c\left\lfloor\frac{a}{c}\right\rfloor+(a\bmod c) a=cca+(amodc) 进行替换。

3.2.2.情况二

a < c a<c a<c b < c b<c b<c 时,令

m = ⌊ ( n − 1 ) a + b c ⌋ m=\left\lfloor\frac{(n-1)a+b}{c}\right\rfloor m=c(n1)a+b

则我们可以推出

g ( a , b , c , n ) = ∑ x = 0 n − 1 x ⌊ a x + b c ⌋ = ∑ x = 0 n − 1 ∑ j = 0 m − 1 x [ j + 1 ≤ ⌊ a x + b c ⌋ ] = ∑ x = 0 n − 1 ∑ j = 0 m − 1 x [ x ≥ ⌊ c j + c − b + a − 1 a ⌋ ] = m n ( n − 1 ) 2 − ∑ j = 0 m − 1 ∑ x = 0 n − 1 x [ x < ⌊ c j + c − b + a − 1 a ⌋ ] \begin{aligned} g(a,b,c,n)&=\sum_{x=0}^{n-1}x\left\lfloor\frac{ax+b}{c}\right\rfloor\\ &=\sum_{x=0}^{n-1}\sum_{j=0}^{m-1}x\left[j+1\le\left\lfloor\frac{ax+b}{c}\right\rfloor\right]\\ &=\sum_{x=0}^{n-1}\sum_{j=0}^{m-1}x\left[x\ge\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right]\\ &=m\frac{n(n-1)}{2}-\sum_{j=0}^{m-1}\sum_{x=0}^{n-1}x\left[x<\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right] \end{aligned} g(a,b,c,n)=x=0n1xcax+b=x=0n1j=0m1x[j+1cax+b]=x=0n1j=0m1x[xacj+cb+a1]=m2n(n1)j=0m1x=0n1x[x<acj+cb+a1]

其中 m n ( n − 1 ) 2 m\frac{n(n-1)}{2} m2n(n1) 的前身是 ∑ j = 0 m − 1 ∑ x = 0 n − 1 x \sum_{j=0}^{m-1}\sum_{x=0}^{n-1}x j=0m1x=0n1x 。由于式子太长,我需要将其简化一下。如果设 p = c − b + a − 1 p=c-b+a-1 p=cb+a1

那么

g ( a , b , c , n ) = n m ( n − 1 ) 2 − ∑ j = 0 m − 1 ∑ x = 0 ⌊ c j + p a ⌋ − 1 x = n m ( n − 1 ) 2 − ∑ j = 0 m − 1 ⌊ c j + p a ⌋ 2 − ⌊ c j + p a ⌋ 2 = n m ( n − 1 ) − h ( c , p , a , m ) + f ( c , p , a , m ) 2 \begin{aligned} g(a,b,c,n)&=\frac{nm(n-1)}{2}-\sum_{j=0}^{m-1}\sum_{x=0}^{\left\lfloor\frac{cj+p}{a}\right\rfloor-1}x\\ &=\frac{nm(n-1)}{2}-\sum_{j=0}^{m-1}\frac{\left\lfloor\frac{cj+p}{a}\right\rfloor^2-\left\lfloor\frac{cj+p}{a}\right\rfloor}{2}\\ &=\frac{nm(n-1)-h(c,p,a,m)+f(c,p,a,m)}{2} \end{aligned} g(a,b,c,n)=2nm(n1)j=0m1x=0acj+p1x=2nm(n1)j=0m12acj+p2acj+p=2nm(n1)h(c,p,a,m)+f(c,p,a,m)

3.3.求 h h h

在求 g g g 的时候用到了哟! h ( a , b , c , n ) = ∑ x = 0 n − 1 ⌊ a x + b c ⌋ 2 h(a,b,c,n)=\sum_{x=0}^{n-1}\left\lfloor\frac{ax+b}{c}\right\rfloor^2 h(a,b,c,n)=x=0n1cax+b2

3.3.1.情况一

a ≥ c a\ge c ac 或者 b ≥ c b\ge c bc 时,显然有……由于式子太长,我不得不使用一些字符来替换。

m a = ⌊ a c ⌋ ,    r a = a   m o d   c m_a=\left\lfloor\frac{a}{c}\right\rfloor,\;r_a=a\bmod c ma=ca,ra=amodc 。我并没有对 b b b 进行操作,是为了让式子尽可能的简单。

h ( a , b , c , n ) = ∑ x = 0 n − 1 ( m a x + ⌊ r a x + b c ⌋ ) 2 = ∑ x = 0 n − 1 ( m a 2 x 2 + 2 m a x ⌊ r a x + b c ⌋ + ⌊ r a x + b c ⌋ 2 ) = n ( n − 1 ) ( 2 n − 1 ) 6 m a 2 + 2 m a g ( r a , b , c , n ) + h ( r a , b , c , n ) \begin{aligned} h(a,b,c,n)&=\sum_{x=0}^{n-1}\left(m_a x+\left\lfloor\frac{r_a x+b}{c}\right\rfloor\right)^2\\ &=\sum_{x=0}^{n-1}\left(m_a^2 x^2+2 m_a x \left\lfloor\frac{r_a x+b}{c}\right\rfloor+\left\lfloor\frac{r_a x+b}{c}\right\rfloor^2\right)\\ &=\frac{n(n-1)(2n-1)}{6}m_a^2+2m_ag(r_a,b,c,n)+h(r_a,b,c,n) \end{aligned} h(a,b,c,n)=x=0n1(max+crax+b)2=x=0n1(ma2x2+2maxcrax+b+crax+b2)=6n(n1)(2n1)ma2+2mag(ra,b,c,n)+h(ra,b,c,n)

为了加速,往往不得不将 b b b 同样进行操作。我直接写最后的式子,读者可以自行推导一下。

h ( a , b , c , n ) = n ( n − 1 ) ( 2 n − 1 ) 6 m a 2 + n m b 2 + h ( r a , r b , c , n ) + n ( n − 1 ) m a m b + 2 m a g ( r a , r b , c , n ) + 2 m b f ( r a , r b , c , n ) \begin{aligned} h(a,b,c,n)=&\frac{n(n-1)(2n-1)}{6}m_a^2\\ &+nm_b^2+h(r_a,r_b,c,n)\\ &+n(n-1)m_a m_b\\ &+2m_a g(r_a,r_b,c,n)\\ &+2 m_b f(r_a,r_b,c,n) \end{aligned} h(a,b,c,n)=6n(n1)(2n1)ma2+nmb2+h(ra,rb,c,n)+n(n1)mamb+2mag(ra,rb,c,n)+2mbf(ra,rb,c,n)

3.3.2.情况二

a < c a<c a<c 并且 b < c b<c b<c 时,仍然是
m = ⌊ ( n − 1 ) a + b c ⌋ m=\left\lfloor\frac{(n-1)a+b}{c}\right\rfloor m=c(n1)a+b

有一个清奇的思路,利用
n 2 = n + 2 ∑ x = 0 n − 1 x n^2=n+2\sum_{x=0}^{n-1}x n2=n+2x=0n1x

将其进行替换。由于式子太长,我不得不使用 p x p_x px 来表示 ⌊ a x + b c ⌋ \left\lfloor\frac{ax+b}{c}\right\rfloor cax+b

h ( a , b , c , n ) = ∑ x = 0 n − 1 ( p x + 2 ∑ j = 0 p x − 1 j ) = f ( a , b , c , n ) + ∑ x = 0 n − 1 ∑ j = 0 m − 1 [ j + 1 ≤ p x ] 2 j = f ( a , b , c , n ) + ∑ j = 0 m − 1 2 j ∑ x = 0 n − 1 [ x ≥ ⌊ c j + c − b + a − 1 a ⌋ ] = f ( a , b , c , n ) + n m ( m − 1 ) − 2 ∑ j = 0 m − 1 j ⌊ c j + c − b + a − 1 a ⌋ = f ( a , b , c , n ) + n m ( m − 1 ) − 2 g ( c , c − b + a − 1 , a , m ) \begin{aligned} h(a,b,c,n)&=\sum_{x=0}^{n-1}\left(p_x+2\sum_{j=0}^{p_x-1}j\right)\\ &=f(a,b,c,n)+\sum_{x=0}^{n-1}\sum_{j=0}^{m-1}\left[j+1\le p_x\right]2j\\ &=f(a,b,c,n)+\sum_{j=0}^{m-1}2j\sum_{x=0}^{n-1}\left[x\ge\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\right]\\ &=f(a,b,c,n)+nm(m-1)-2\sum_{j=0}^{m-1}j\left\lfloor\frac{cj+c-b+a-1}{a}\right\rfloor\\ &=f(a,b,c,n)+nm(m-1)-2g(c,c-b+a-1,a,m) \end{aligned} h(a,b,c,n)=x=0n1(px+2j=0px1j)=f(a,b,c,n)+x=0n1j=0m1[j+1px]2j=f(a,b,c,n)+j=0m12jx=0n1[xacj+cb+a1]=f(a,b,c,n)+nm(m1)2j=0m1jacj+cb+a1=f(a,b,c,n)+nm(m1)2g(c,cb+a1,a,m)

3.4.一起求

因为 g g g h h h 会互相使用,而且还需要引用 f f f,非常麻烦。建议一起进行求解,大大降低复杂度。

虽然我们并没有用到 b b b 的正负性,但是,可以发现,如果最初的 b b b 是正数,则递归过程中的所有 b b b 都是正数(毕竟 c − b + a − 1 c-b+a-1 cb+a1 a < c a<c a<c b < c b<c b<c 情形下出现)。

为了方便代码实现,在此处将三种一起汇总,并且 肆无忌惮地 使用如下符号简化式子:

  • m a = ⌊ a c ⌋ ,    r a = a   m o d   c m_a=\lfloor\frac{a}{c}\rfloor,\;r_a=a\bmod c ma=ca,ra=amodc m b , r b m_b,r_b mb,rb 的规定同理。
  • p = c − b + a − 1 p=c-b+a-1 p=cb+a1
  • p 1 = n ,    p 2 = n ( n − 1 ) 2 ,    p 3 = n ( n − 1 ) ( 2 n − 1 ) 6 p_1=n,\;p_2=\frac{n(n-1)}{2},\;p_3=\frac{n(n-1)(2n-1)}{6} p1=n,p2=2n(n1),p3=6n(n1)(2n1)

3.4.1.情况一

a ≥ c a\ge c ac b ≥ c b\ge c bc 时,

f ( a , b , c , n ) = p 2 m a + p 1 m b + f ( r a , r b , c , n ) f(a,b,c,n)=p_2m_a+p_1m_b+f(r_a,r_b,c,n) f(a,b,c,n)=p2ma+p1mb+f(ra,rb,c,n)

g ( a , b , c , n ) = p 3 m a + p 2 m b + g ( r a , r b , c , n ) g(a,b,c,n)=p_3m_a+p_2m_b+g(r_a,r_b,c,n) g(a,b,c,n)=p3ma+p2mb+g(ra,rb,c,n)

h ( a , b , c , n ) = p 3 m a 2 + 2 p 2 m a m b + p 1 m b 2 + 2 m b f ( r a , r b , c , n ) + 2 m a g ( r a , r b , c , n ) + h ( r a , r b , c , n ) \begin{aligned} &h(a,b,c,n)=p_3m_a^2+2p_2m_a m_b+p_1m_b^2\\ +2 m_b &f(r_a,r_b,c,n)+2m_a g(r_a,r_b,c,n)+h(r_a,r_b,c,n) \end{aligned} +2mbh(a,b,c,n)=p3ma2+2p2mamb+p1mb2f(ra,rb,c,n)+2mag(ra,rb,c,n)+h(ra,rb,c,n)

3.4.2.情况二

a < c a<c a<c 并且 b < c b<c b<c 时,令

m = ⌊ ( n − 1 ) a + b c ⌋ m=\left\lfloor\frac{(n-1)a+b}{c}\right\rfloor m=c(n1)a+b

则有

f ( a , b , c , n ) = n m − f ( c , p , a , m ) f(a,b,c,n)=nm-f(c,p,a,m) f(a,b,c,n)=nmf(c,p,a,m)

g ( a , b , c , n ) = n m ( n − 1 ) − h ( c , p , a , m ) + f ( c , p , a , m ) 2 g(a,b,c,n)=\frac{nm(n-1)-h(c,p,a,m)+f(c,p,a,m)}{2} g(a,b,c,n)=2nm(n1)h(c,p,a,m)+f(c,p,a,m)

h ( a , b , c , n ) = n m ( m − 1 ) − 2 g ( c , p , a , m ) + f ( a , b , c , n ) h(a,b,c,n)=nm(m-1)-2g(c,p,a,m)+f(a,b,c,n) h(a,b,c,n)=nm(m1)2g(c,p,a,m)+f(a,b,c,n)

4.代码

struct LL{
	long long x;
	LL(const long long &num=0):x(num%Mod){}
	operator long long(){ return x; }
	LL operator * (long long num){
		return LL(x*(num%Mod)%Mod);
	}
	LL operator + (long long num){
		return LL((x+num%Mod+Mod)%Mod);
	}
	LL operator - (long long num){
		return LL((x-num%Mod+Mod)%Mod);
	}
}; // 注意:LL会强制性取模,所以long long也仍然在被使用
struct PPL{ LL f, g, h; PPL(){ f = g = h = 0; } };
PPL likeGcd(long long a,long long b,long long c,long long n){
	if(n == 0) return PPL(); // 没有项数……
	long long m = ((n-1)*a+b)/c;
	if(a >= c or b >= c){
		LL ma = a/c, mb = b/c;
		LL yi = LL(n), er = yi*(n-1)*inv2;
		LL san = er*(2*n-1)*inv3;
		auto res = likeGcd(a%c,b%c,c,n);
		res.h = res.h+mb*res.f*2ll+ma*res.g*2ll;
		res.h = res.h+san*ma*ma+er*ma*mb*2ll+yi*mb*mb;
		res.f = res.f+er*ma+yi*mb;
		res.g = res.g+san*ma+er*mb;
		return res;
	}
	else{
		if(a == 0) return PPL();
		auto last = likeGcd(c,c-b+a-1,a,m);
		PPL now; LL cs = LL(n)*m;
		now.f = cs-last.f;
		now.g = (cs*(n-1)-last.h+last.f)*inv2;
		now.h = cs*(m-1)-last.g*2ll+now.f;
		return now;
	}
}

5.进阶

5.1.讲解

传送门 to ZZQ’blog:更通用的,求
∑ x = 0 n x p ⋅ ⌊ a x + b c ⌋ q \sum_{x=0}^{n}x^{p}\cdot\left\lfloor\frac{ax+b}{c}\right\rfloor^q x=0nxpcax+bq

记其为 f ( p , q , a , b , c , n ) f(p,q,a,b,c,n) f(p,q,a,b,c,n) a ≥ c ∨ b ≥ c a\ge c\vee b\ge c acbc 时,需要利用二项式展开化简,挺麻烦的。下面假设 a < c ∧ b < c a<c\wedge b<c a<cb<c 。注意:虽然 b b b 并不参与复杂度计算,但是为了下面的式子成立,必须要每一项都大于零(否则 ∑ x p \sum x^p xp 会出问题)。我就这样 W A \rm WA WA 穿了,顶你个肺啊!

如果仍然要用 j ≤ ⌊ a x + b c ⌋ j\le\lfloor\frac{ax+b}{c}\rfloor jcax+b 来化简,那么 j j j 上面所附加的权值是什么呢?好像并没有一个很 t r i c k y \rm tricky tricky 的方案,不如就平凡地令其为 j q − ( j − 1 ) q j^q-(j-1)^q jq(j1)q 吧!

仍然记 m = ⌊ a n + b c ⌋ m=\lfloor{an+b\over c}\rfloor m=can+b,即最大的一项。

f ( p , q , a , b , c , n ) = ∑ x = 0 n x p    ∑ j = 1 m [ j ≤ ⌊ a x + b c ⌋ ]    [ j q − ( j − 1 ) q ] = ∑ j = 1 m [ j q − ( j − 1 ) q ] ∑ x = 1 n x p [ c j − b − 1 < a x ] = ∑ j = 0 m − 1 [ ( j + 1 ) q − j q ] ( ∑ x = 0 n x p − ∑ x = 0 ⌊ c j + c − b − 1 a ⌋ x p ) f(p,q,a,b,c,n) =\sum_{x=0}^{n}x^p\;\sum_{j=1}^{m}\left[j\le \left\lfloor\frac{ax+b}{c}\right\rfloor\right]\;[j^q-(j-1)^q]\\ =\sum_{j=1}^{m}[j^q-(j-1)^q]\sum_{x=1}^{n}x^p\left[cj-b-1<ax\right]\\ =\sum_{j=0}^{m-1}[(j+1)^q-j^q]\left(\sum_{x=0}^{n}x^p-\sum_{x=0}^{\lfloor{cj+c-b-1\over a}\rfloor}x^p\right) f(p,q,a,b,c,n)=x=0nxpj=1m[jcax+b][jq(j1)q]=j=1m[jq(j1)q]x=1nxp[cjb1<ax]=j=0m1[(j+1)qjq]x=0nxpx=0acj+cb1xp

题外话:发现最麻烦的是 x x x 的范围到底 要不要包含零?以及 0 0 0^0 00 该算什么?因为这个考虑,我最终又把 j j j 的范围改成了从零开始。

第一项, j , x j,x j,x 是独立的,可以分开求和然后相乘。第二项,好像比较复杂,可是回想一下,我们既然是要递归,那就要把它跟 ⌊ c j + c − b − 1 a ⌋ \lfloor{cj+c-b-1\over a}\rfloor acj+cb1,也就是 x x x 的取值范围,构建关联。这很简单——事先解出 ∑ x ≤ n x p \sum_{x\le n}x^p xnxp 关于 n n n 的多项式,将每一项代入,都是递归子问题。

对于左边的 ( j + 1 ) q (j+1)^q (j+1)q j q j^q jq 两项,要注意了,必须二项式展开,变为 j j j 的多项式,才能递归。否则,我们要递归 ( j + 1 ) q (j+1)^q (j+1)q 则必须是 ⌊ c ( j + 1 ) − b − 1 a ⌋ \lfloor\frac{c(j+1)-b-1}{a}\rfloor ac(j+1)b1 p ′ p' p 次幂,那就是 f ( q , p ′ , c , − b − 1 , a , m − 1 ) f(q,p',c,-b-1,a,m-1) f(q,p,c,b1,a,m1) 的事儿,递归两次的话,复杂度就爆炸了!

所以 f ( p , q , a , b , c , n ) f(p,q,a,b,c,n) f(p,q,a,b,c,n) 要用到 f ( q ′ , p ′ , c , c − b − 1 , a , m − 1 )    ( q ′ < q ,    p ′ ≤ p + 1 ) f(q',p',c,c-b-1,a,m-1)\;(q'<q,\;p'\le p+1) f(q,p,c,cb1,a,m1)(q<q,pp+1) 。那么我们可以对于 a , b , c , n a,b,c,n a,b,c,n 求出所有 p + q ≤ v 0 p+q\le v_0 p+qv0 的值。复杂度则为 O ( v 0 4 log ⁡ ( a + c ) ) \mathcal O(v_0^4\log(a+c)) O(v04log(a+c))

对于预处理 ∑ x p \sum x^p xp,我觉得利用这个计算方法还挺不错的,当然你可以有更好的想法。

5.2.实现

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cassert>
using namespace std;
typedef long long int_;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int Mod = 1e9+7;
inline int qkpow(int_ b,int q){
	int a = 1; b %= Mod;
	for(; q; q>>=1,b=b*b%Mod)
		if(q&1) a = a*b%Mod;
	return a;
}

const int MaxN = 50;
namespace Math{
	int c[MaxN][MaxN], inv[MaxN];
	int poly[MaxN][MaxN+1]; 
	
	void import(int n){
		rep(i,0,n) rep(j,c[i][0]=1,i)
			c[i][j] = (c[i-1][j]+c[i-1][j-1])%Mod;
		poly[0][0] = poly[0][1] = 1; // \sum_{x} x^0 = n+1
		for(int k=inv[1]=1; k<=n; ++k){
			inv[k+1] = (0ll+Mod-Mod/(k+1))
				*inv[Mod%(k+1)]%Mod;
			rep(j,0,k+1) poly[k][j] = c[k+1][j];
			rep(j,0,k-1) rep(i,0,j+1)
				poly[k][i] = (poly[k][i]+Mod-1ll*
					poly[j][i]*c[k+1][j]%Mod)%Mod;
			rep(j,0,k+1) poly[k][j] = 1ll*
				poly[k][j]*inv[k+1]%Mod;
		}
	}
	int valueAt(int id,int x){
		int res = 0, v = 1;
		for(int i=0; i<=id+1; ++i,v=1ll*v*x%Mod)
			res = (res+1ll*v*poly[id][i])%Mod;
		return res;
	}
}

int res[MaxN][MaxN], tmp[MaxN][MaxN];
void likeGcd(int v0,int a,int b,int c,int_ n){
	if(a == 0 || n == 0){
		b /= c; // constant
		rep(p,0,v0) rep(q,0,v0-p)
			res[p][q] = 1ll*qkpow(b,q)
				*Math::valueAt(p,n)%Mod;
		return ;
	}
	if(b >= c){ // don't ignore this!!!
		likeGcd(v0,a,b%c,c,n);
		rep(p,0,v0) memset(tmp[p]+1,0,v0<<2);
		rep(p,0,v0) rep(q,1,v0-p)
		for(int i=0,x=1; i<=q; ++i){
			tmp[p][q] = (tmp[p][q]+1ll*x*
				Math::c[q][i]%Mod*res[p][q-i])%Mod;
			x = 1ll*x*(b/c)%Mod; // attached value
		}
		rep(p,0,v0) tmp[p][0] = Math::valueAt(p,n);
		swap(res,tmp); return ;
	}
	if(a >= c){
		likeGcd(v0,a%c,b,c,n);
		rep(p,0,v0) memset(tmp[p]+1,0,v0<<2);
		rep(p,0,v0) rep(q,1,v0-p)
		for(int i=0,x=1; i<=q; ++i){
			tmp[p][q] = (tmp[p][q]+1ll*x*
				Math::c[q][i]%Mod*res[p+i][q-i])%Mod;
			x = 1ll*x*(a/c)%Mod; // attached value
		}
		rep(p,0,v0) tmp[p][0] = Math::valueAt(p,n);
		swap(res,tmp); return ;
	}
	int_ m = (1ll*a*n+b)/c; // max one
	if(c*m > 1ll*a*n+b) -- m;
	likeGcd(v0,c,c-b-1,a,m-1);
	rep(p,0,v0) rep(q,0,v0-p){
		tmp[p][q] = Math::valueAt(p,n);
		tmp[p][q] = 1ll*tmp[p][q]*qkpow(m,q)%Mod;
		rep(j,0,q-1) rep(i,0,p+1){
			int wxk = 1ll*Math::c[q][j]
				*Math::poly[p][i]%Mod*res[j][i]%Mod;
			tmp[p][q] = (tmp[p][q]+Mod-wxk)%Mod;
		}
	}
	swap(res,tmp); return ;
}

6.例题

答案?什么答案?例题的参考答案?读者自证不难啊!

6.1.模板题

传送门 to luogu:就用上面的模板代码就可以了。

6.2.进阶版

传送门 to LOJ:板题。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值