[SDOI2018]旧试题

题意

求如下表达式的值

\[\sum_{i=1}^A \sum_{j=1}^B \sum_{k=1}^Cd(ijk)\pmod {10^9+7} \]

其中, \(A,B,C \leqslant 10^5\)

solution

先考虑如何处理后面的\(d(ijk)\)

根据[SDOI]2015约数个数和可知,通过简单的映射关系,有,

\[d(ijk) = \sum_{u|i}\sum_{v|j}\sum_{w|k}[gcd(u, v)=1]\times[gcd(u,w)=1]\times[gcd(v,w)=1] \]

则有,

\[\sum_{i=1}^A \sum_{j=1}^B \sum_{k=1}^Cd(ijk) \]

\[= \sum_{i=1}^A \sum_{j=1}^B \sum_{k=1}^C \sum_{u|i}\sum_{v|j}\sum_{w|k}[gcd(u, v)=1]\times[gcd(u,w)=1]\times[gcd(v,w)=1])) \]

\[= \sum_{i=1}^A \sum_{j=1}^B \sum_{k=1}^C \sum_{u|i}\sum_{v|j}\sum_{w|k}\epsilon(gcd(u, v))\times\epsilon(gcd(u,w))\times\epsilon(gcd(v,w)) \]

根据莫比乌斯反演的经典小把戏,尝试把因子提前枚举,

\[= \sum_{u=1}^A \sum_{v=1}^B \sum_{w=1}^C \sum_{u|i} \sum_{v|j} \sum_{w|k} \epsilon(gcd(u, v))\times\epsilon(gcd(u,w))\times\epsilon(gcd(v,w)) \]

\[= \sum_{u=1}^A \sum_{v=1}^B \sum_{w=1}^C \lfloor \frac{A}{u} \rfloor \lfloor \frac{B}{v} \rfloor \lfloor \frac{C}{w} \rfloor \epsilon(gcd(u, v))\epsilon(gcd(u,w))\epsilon(gcd(v,w)) \]

由莫比乌斯反演的基本推论:

\[\sum_{i=1}^{A} \sum_{j=1}^{B} \epsilon(gcd(i,j)) = \sum_{i=1}^{A} \sum_{j=1}^{B} \sum_{d|gcd(i,j)} \mu(d) = \sum_{i=1}^{A} \sum_{j=1}^{B} \sum_{d|i , d|j} \mu(d) \]

则有,

\[= \sum_{u=1}^A \sum_{v=1}^B \sum_{w=1}^C \lfloor \frac{A}{u} \rfloor \lfloor \frac{B}{v} \rfloor \lfloor \frac{C}{w} \rfloor \sum_{a|u,a|v} \mu(a) \sum_{b|u,b|w} \mu(b) \sum_{c|v,c|w} \mu(c) \]

再次交换求和号,

\[=\sum_{a=1}^{min\{A,B\}} \sum_{b=1}^{min\{A,C\}} \sum_{c=1}^{min\{B,C\}} \mu(a) \ \mu(b) \ \mu(c) \ \sum_{lcm(a,b)|u} \lfloor \frac{A}{u} \rfloor \sum_{lcm(a,c)|v} \lfloor \frac{B}{v} \rfloor \sum_{lcm(b,c)|w} \lfloor \frac{C}{w} \rfloor \]

\[=\sum_{a=1}^{min\{A,B\}} \sum_{b=1}^{min\{A,C\}} \sum_{c=1}^{min\{B,C\}} \mu(a) \ \mu(b) \ \mu(c) \ \sum_{u} \lfloor \frac{A}{u\times lcm(a,b)} \rfloor \sum_{v} \lfloor \frac{B}{v \times lcm(a,c)} \rfloor \sum_{w} \lfloor \frac{C}{w \times lcm(b,c)} \rfloor \]

\(F(n)=\sum_{i} \lfloor \frac{n}{i} \rfloor = \sum_{i=1}^{n}d(i)\),则有,

\[=\sum_{a=1}^{min\{A,B\}} \sum_{b=1}^{min\{A,C\}} \sum_{c=1}^{min\{B,C\}} \mu(a) \ \mu(b) \ \mu(c) \ F(\lfloor \frac{A}{lcm(a,b)} \rfloor) F(\lfloor \frac{B}{lcm(a,c)} \rfloor) F(\lfloor \frac{C}{lcm(b,c)} \rfloor) \]

然后经过一顿操作,一个\(O(n^3)\)成功变成了另一个\(O(n^3)\)的式子

但是可以通过\(O(n \log n)\)的预处理,提前计算出所有\(F(n)\)的值,至少更加便于处理了

考虑这个式子值非零的条件,则\((a,b,c)\)需要满足:

\[\mu(a) \ne 0 , \mu(b) \ne 0, \mu(c) \ne 0, lcm(a,b) \leqslant A, lcm(a,c) \leqslant B, lcm(b, c) \leqslant C \]

后面三个条件不容易考虑,可以从前三个条件下手,不难发现\(a,b,c\)都必须为若干指数为\(1\)的质数的积

不难有暴力dfs,暴力枚举质数的积,然后分别计算其对应的式子的值,时间复杂度为\(O(9592^7)\),甚至不如\(O(n^3)\)的时间效率好

那么考虑一些优化技巧,或许能够发现我们可以在\(max\{A,B,C\}\)较小时,使用\(O(n^3)\)进行枚举,而对于其值较大时,考虑使用暴力dfs解决问题,分别来考虑:

\(f(A,B,C) = \sum_{i=1}^A \sum_{j=1}^B \sum_{k=1}^Cd(ijk)\)

对于\(O(n^3)\)枚举部分,利用本题答案的定义式,根据容斥定理,则有,

\[f(A,B,C) = \sum_{m_i \in M}(-1)^{\tau(m_i)-1} \times f(A - m_{i,1}, B - m_{i,2}, C - m_{i,3}) + d(ABC) \]

其中,\(M\)为除\(\{0,0,0\}\)外其他由三个\(0\)\(1\)组成的\(7\)个有限数列的集合,\(m_i\)为集合中的一个有限数列,\(\tau(i)\)\(m_i\)\(1\)的数量

(写的还不如说的明白,那写个锤子的数学表达式...)

这样便\(O(n^3)\)的时间复杂度下解决了较小\(max\{A,B,C\}\)下的值的求解

接下来解决\(max\{A,B,C\}\)较大时暴力dfs的求解,考虑到原定义式的运算规模较大,我们可以通过推出式来进行爆搜

简化问题规模,对于某个特定质数因子\(p_i\),分别考虑\(a,b,c\)中是否含有因子\(p\),不妨先假设\(a\)中含有质因子\(p\),那么对于这个特定\(a\)的值存在等式,

\[g(A,B,C) \]

\[=\sum_{b=1}^{min\{A,C\}} \sum_{c=1}^{min\{B,C\}} \mu(a) \ \mu(b) \ \mu(c) \ F(\lfloor \frac{A}{lcm(a,b)} \rfloor) F(\lfloor \frac{B}{lcm(a,c)} \rfloor) F(\lfloor \frac{C}{lcm(b,c)} \rfloor) \]

\[=\sum_{b=1}^{min\{A,C\}} \sum_{c=1}^{min\{B,C\}} (-1) \ \mu(\frac{a}{p}) \ \mu(b) \ \mu(c) \ F(\lfloor \frac{A}{lcm(\frac{a}{p},b) \times p} \rfloor) F(\lfloor \frac{B}{lcm(\frac{a}{p},c) \times p} \rfloor) F(\lfloor \frac{C}{lcm(b,c)} \rfloor) \]

\[=-g(\frac{A}{p}, \frac{B}{p}, C) \]

显然对于任意的\(a\),对于任意的质数因子\(p\),该等式同步成立,则有,

\[G(A,B,C) = \sum_{p|a}^A g(A, B, C) = -\sum_{p|a}^A g(\lfloor \frac{A}{p} \rfloor, \lfloor \frac{B}{p} \rfloor, C) = -G(\lfloor \frac{A}{p} \rfloor , \lfloor \frac{B}{p} \rfloor, C) \]

显然,对于\(b,c\),该性质同步存在,记\(i\)为当前筛选到第\(i\)个质数\(p_i\)\(dfs(i, A, B, C)\)为筛选到\(p_i\)\(f(A,B,C)\)的值,不难设计dfs方案,

\[dfs(i,A,B,C) = \sum_{m_i \in M}(-1)^{\tau(m_i)} \times dfs(i + 1, \lfloor \frac{A}{p^{m_{i,1} \lor m_{i,2}} }\rfloor, \lfloor \frac{B}{p^{m_{i,1} \lor m_{i,3}}} \rfloor, \lfloor \frac{C}{p ^ {m_{i,2} \lor m_{i,3} }}\rfloor) \]

其中,\(M\)为全体由三个\(0\)\(1\)组成的\(8\)个有限数列的集合,\(m_i\)为集合中的一个有限数列,\(\tau(i)\)\(m_i\)\(1\)的数量

当遍历完全部质数时,无论剩余的范围为多大,显然只能由\((a=1, b=1, c=1)\)做出贡献\(F(A) \times F(B) \times F(C)\),否则其\(\mu\)值为\(0\)

不难计算,这个暴力dfs的时间复杂度为\(O(8^{9592})\),但是由于\(A,B,C\)上界的存在,实际运行效率远优于此,但是在本题还是无法通过,考虑剪枝:

  1. 由于我们已经对\(max\{A,B,C\}\)较小时的方案进行了预处理,显然我们优先考虑较大的质数会使得整个搜索树更小

  2. 当目前遍历到的素数\(p_i \geqslant max\{A,B,C\}\)时,显然可以直接返回我们先前的预处理值\(f(A,B,C)\),否则会因为已经除去部分因子而导致我们的预处理值发生改变

  3. 发现当\(a,b,c\)中有至少两个数字可以被\(p\)整除时,不难发现dfs的返回值不变,只有符号发生变化,可以只递归一次dfs,然后将返回值两倍加入当前的答案

在这些剪枝的基础下,代码可以跑的飞快,完全不需要经历痛苦的卡常过程就可以A掉这题

Code

点击查看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

const int N = 1e5 + 50;
const int M = 31;
const int mod = 1e9 + 7;

inline int read() {
	int res = 0, f = 1;
	char c = getchar();
	while (c > '9' || c < '0') {
		if (c == '-')  f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		res = (res << 3) + (res << 1) + c - '0';
		c = getchar();
	}	
	return res * f;
}

inline int add_mod(int a, int b) {
	a += b;
	if (a < 0)  a += mod;
	if (a >= mod)  a -= mod;
	return a;
}
inline int del_mod(int a, int b) {
	a -= b;
	if (a < 0)  a += mod;
	if (a >= mod)  a -= mod;
	return a;
}
inline int mul_mod(int a, int b) {
	a = 1ll * a * b % mod;
	return a;
}

int num;
int prime[N], d[N];
bool v[N];

int f[N];
int dp[M][M][M];

void init() {
	int n = 1e5;
	for (int i = 1; i <= n; ++i)  d[i] = 1;
	for (int i = 2; i <= n; ++i) {
		if (!v[i]) {
			prime[++num] = i;
			for (int j = 1; j <= n / i; ++j) {
				v[i * j] = 1;
				d[i * j] += d[j];
			}
		}
	}
	for (int i = 1; i <= n; ++i)  f[i] = add_mod(f[i - 1], d[i]);
	reverse(prime + 1, prime + 1 + num);
	for (int i = 1; i < M; ++i)
		for (int j = 1; j < M; ++j)	
			for (int k = 1; k < M; ++k)
				dp[i][j][k] = (0ll + dp[i - 1][j][k] + dp[i][j - 1][k] + dp[i][j][k - 1] - dp[i - 1][j - 1][k] - dp[i - 1][j][k - 1] - dp[i][j - 1][ k - 1] + dp[i - 1][j - 1][k - 1] + d[i * j * k]) % mod;
}

inline int dfs(int nw, int a, int b, int c) {
	int maxx = max(max(a, b), c);
	if (!a || !b || !c)  return 0;
	if (!prime[nw])  return mul_mod(f[a], mul_mod(f[b], f[c]));
	if (prime[nw] > maxx && maxx < M)  return dp[a][b][c];
	int res = dfs(nw + 1, a, b, c);
	if (a >= prime[nw] && b >= prime[nw])  res = del_mod(res, dfs(nw + 1, a / prime[nw], b / prime[nw], c));
	if (a >= prime[nw] && c >= prime[nw])  res = del_mod(res, dfs(nw + 1, a / prime[nw], b, c / prime[nw]));
	if (b >= prime[nw] && c >= prime[nw])  res = del_mod(res, dfs(nw + 1, a, b / prime[nw], c / prime[nw]));
	if (a >= prime[nw] && b >= prime[nw] && c >= prime[nw]) res = add_mod(res, mul_mod(dfs(nw + 1, a / prime[nw], b / prime[nw], c / prime[nw]), 2));
	return res;
}

int A, B, C;

int main () {
	init();
	int T = read();
	while (T--) {
		A = read(), B = read(), C = read();
		int cnt = 1;
		while (prime[cnt] > A && prime[cnt] > B && prime[cnt] > C)  ++cnt;
		printf("%d\n", dfs(cnt, A, B, C));
	}
    return 0;
}

杂记

感谢_rqy的博客提供的idea,清芷姐姐太强力(说实话真没看懂rqy博客的细节内容,细节都是自己一点一点填的)

上次写赛博笔记都已经是三年半之前了,时间过得真快啊

顺便闲的没事搞了一个cnblogs,顺手发上去叭

posted @ 2023-05-31 22:34  A_Big_Jiong  阅读(46)  评论(2编辑  收藏  举报