【题解】P6042 「ACOI2020」学园祭

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=1nj=1ik=1jgcd((ij)!,(jk)!)
T T T 组数据。 T , n ≤ 1 0 6 T,n\le 10^6 T,n106

题解

易得
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=1nj=1ik=1jmin(ij,jk)!
x = i − j , y = j − k x=i-j,y=j-k x=ij,y=jk。显然 x , y ≥ 0 , x + y = i − k ≤ n − 1 x,y\ge 0,x+y=i-k\le n-1 x,y0,x+y=ikn1

那么 0 ≤ min ⁡ ( x , y ) ≤ ⌊ n − 1 2 ⌋ 0\le \min(x,y)\le \lfloor\frac{n-1}{2}\rfloor 0min(x,y)2n1

考虑枚举 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=02n1d!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 in,所以 x + y + k ≤ n x+y+k\le n x+y+kn,所以 k ≤ n − x − y k\le n-x-y knxy。即对于一组确定的 x , y x,y x,y,有 n − x − y n-x-y nxy 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 yd,因为 x + y ≤ n − 1 x+y\le n-1 x+yn1,所以 d ≤ y ≤ n − x − 1 d\le y\le n-x-1 dynx1,所以 y y y n − x − 1 − d + 1 = n − x − d = n − 2 d n-x-1-d+1=n-x-d=n-2d nx1d+1=nxd=n2d 种取值。那么对于所有的 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} dn2d=2(n2d+1)(n2d) 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 n2d 即可。

现在有
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=22(n2d+1)(n2d)(n2d)=(n2d)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=02n1d!(n2d)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=02n1(n2d!d!4nd+d!4d2)=n2d=02n1d!4nd=02n1d!d+4d=02n1d!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 2n1 写成了 ⌊ 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;
}

总结

  • 这题只要敢推式子就能做。思路非常明显。

你可能感兴趣的:(题解,算法)