link
求
∑ i = 1 n ∑ j = 1 i ∑ k = 1 j gcd ( ( i − j ) ! , ( j − k ) ! ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{i}\sum\limits_{k=1}^{j}\gcd((i-j)!,(j-k)!) i=1∑nj=1∑ik=1∑jgcd((i−j)!,(j−k)!)
T T T 组数据。 T , n ≤ 1 0 6 T,n\le 10^6 T,n≤106。
易得
a n s = ∑ i = 1 n ∑ j = 1 i ∑ k = 1 j min ( i − j , j − k ) ! ans =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{i}\sum\limits_{k=1}^{j}\min(i-j,j-k)! ans=i=1∑nj=1∑ik=1∑jmin(i−j,j−k)!
记 x = i − j , y = j − k x=i-j,y=j-k x=i−j,y=j−k。显然 x , y ≥ 0 , x + y = i − k ≤ n − 1 x,y\ge 0,x+y=i-k\le n-1 x,y≥0,x+y=i−k≤n−1。
那么 0 ≤ min ( x , y ) ≤ ⌊ n − 1 2 ⌋ 0\le \min(x,y)\le \lfloor\frac{n-1}{2}\rfloor 0≤min(x,y)≤⌊2n−1⌋。
考虑枚举 d = min ( x , y ) d=\min(x,y) d=min(x,y),计算对于每个 d d d 有多少种 i , j , k i,j,k i,j,k 的取值方案 c n t d cnt_d cntd。
a n s = ∑ d = 0 ⌊ n − 1 2 ⌋ d ! ⋅ c n t d ans=\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}d!\cdot cnt_d ans=d=0∑⌊2n−1⌋d!⋅cntd
对于一组确定的 x , y x,y x,y,若我们能确定 k k k 的值,那么有 j = y + k , i = x + j = x + y + k j=y+k,i=x+j=x+y+k j=y+k,i=x+j=x+y+k,也就是确定一个 k k k 即可确定一组 i , j , k i,j,k i,j,k。因为 i ≤ n i\le n i≤n,所以 x + y + k ≤ n x+y+k\le n x+y+k≤n,所以 k ≤ n − x − y k\le n-x-y k≤n−x−y。即对于一组确定的 x , y x,y x,y,有 n − x − y n-x-y n−x−y 组 i , j , k i,j,k i,j,k 与之对应。
考虑对于确定的 d d d,有多少组 x , y x,y x,y。不妨假设 x = d x=d x=d,则 y y y 显然满足 y ≥ d y\ge d y≥d,因为 x + y ≤ n − 1 x+y\le n-1 x+y≤n−1,所以 d ≤ y ≤ n − x − 1 d\le y\le n-x-1 d≤y≤n−x−1,所以 y y y 有 n − x − 1 − d + 1 = n − x − d = n − 2 d n-x-1-d+1=n-x-d=n-2d n−x−1−d+1=n−x−d=n−2d 种取值。那么对于所有的 d d d,当 x = d x=d x=d 时总共的方案为 ∑ d n − 2 d = ( n − 2 d + 1 ) ( n − 2 d ) 2 \sum\limits_{d} n-2d=\dfrac{(n-2d+1)(n-2d)}{2} d∑n−2d=2(n−2d+1)(n−2d)。 x x x 取 d d d 与 y y y 取 d d d 的方案是一样的,所以直接乘 2 2 2。注意这里对于 x = y = d x=y=d x=y=d 的方案算了两次,减去 n − 2 d n-2d n−2d 即可。
现在有
c n t d = 2 ⋅ ( n − 2 d + 1 ) ( n − 2 d ) 2 − ( n − 2 d ) = ( n − 2 d ) 2 cnt_d=2\cdot\dfrac{(n-2d+1)(n-2d)}{2}-(n-2d)=(n-2d)^2 cntd=2⋅2(n−2d+1)(n−2d)−(n−2d)=(n−2d)2
所以现在有
a n s = ∑ d = 0 ⌊ n − 1 2 ⌋ d ! ⋅ ( n − 2 d ) 2 ans=\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}d!\cdot (n-2d)^2 ans=d=0∑⌊2n−1⌋d!⋅(n−2d)2
看起来现在可以 O ( T n ) O(Tn) O(Tn) 解决这个问题了。
只需要再进一步推导:
a n s = ∑ d = 0 ⌊ n − 1 2 ⌋ ( n 2 d ! − d ! 4 n d + d ! 4 d 2 ) = n 2 ∑ d = 0 ⌊ n − 1 2 ⌋ d ! − 4 n ∑ d = 0 ⌊ n − 1 2 ⌋ d ! ⋅ d + 4 ∑ d = 0 ⌊ n − 1 2 ⌋ d ! ⋅ d 2 ans=\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}(n^2d!-d!4nd+d!4d^2)\\ =n^2\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}d!-4n\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}d!\cdot d+4\sum\limits_{d=0}^{\lfloor\frac{n-1}{2}\rfloor}d!\cdot d^2 ans=d=0∑⌊2n−1⌋(n2d!−d!4nd+d!4d2)=n2d=0∑⌊2n−1⌋d!−4nd=0∑⌊2n−1⌋d!⋅d+4d=0∑⌊2n−1⌋d!⋅d2
于是只需要预处理三个 ∑ \sum ∑ 的前缀和就能 O ( 1 ) O(1) O(1) 询问啦。总时间复杂度 O ( n + T ) O(n+T) O(n+T)。
注意阶乘求和不要忘了 0 0 0 的阶乘。long long
要开够。
然鹅我把 ⌊ n − 1 2 ⌋ \lfloor\frac{n-1}{2}\rfloor ⌊2n−1⌋ 写成了 ⌊ n 2 ⌋ \lfloor\frac{n}{2}\rfloor ⌊2n⌋ 竟然还过了。
#include
using namespace std;
typedef long long LL;
const int N = 1000005;
const LL mod = 10086001;
int T;
LL f1[N], f2[N], sf[N], n;
void init() {
sf[0] = 1;
for (LL i = 1, fac = 1; i < (N >> 1); i++, fac = fac * i % mod)
sf[i] = (sf[i - 1] + fac) % mod,
f1[i] = (f1[i - 1] + i * i % mod * fac) % mod,
f2[i] = (f2[i - 1] + i * fac) % mod;
}
int main() {
init();
scanf("%d", &T);
while (T--)
scanf("%lld", &n),
printf("%lld\n", ((n * n % mod * sf[(n - 1) >> 1] % mod + 4 * f1[(n - 1) >> 1] % mod - 4 * n * f2[(n - 1) >> 1] % mod) % mod + mod) % mod);
return 0;
}