CF235E

这道题正解本来是莫比乌斯反演,但是被神犇 @Aurora_Sley 暴力吊打标算艹过去了(

先筛出来 \(1\sim 2000\) 的所有质数,第 \(i\) 个质数记为 \(Prime_i\)

\(f[x][a][b][c]\) 表示当前考虑到 \(Prime_x,\sum\limits^a_{i=1}\sum\limits^b_{j=1}\sum\limits^c_{k=1}d(ijk)\) 的值。

这里的 \(d(ijk)\) 表示因数中不是 \(Prime_{x+1},Prime_{x+2}...\) 倍数的因数个数。

转移为 \(f[x][a][b][c]=\sum\limits_i\sum\limits_j\sum\limits_k f[x-1][\frac{a}{x^i}][\frac{b}{x^j}][\frac{c}{x^k}](i+j+k+1)\)

当然 \(x\) 是从大枚举到小的。

这里状态存不下,采用记搜+unordered_map处理。

然后我们发现这个 \(O(n^3\pi(N)(\log n)^3)\) 的算法过了,而且900ms,跑得飞快(手写哈希更快),吊打标算至少比 kzsn 的标算块

#pragma GCC optimize(3)
#include <cstdio>
#include <unordered_map>

const int mod = 1 << 30;
std::unordered_map<int, long long> f[305];
int Prime[305], cnt;
int dfs(const int p, int a, int b, int c) {
	if (a > b) a ^= b ^= a ^= b;
	if (a > c) a ^= c ^= a ^= c;
	if (b > c) b ^= c ^= b ^= c;
	if (!p) return 1;
	int t = Prime[p], code = a * 4000000 + b * 2000 + c, ans = 0;
	if (f[p].count(code)) return f[p][code];
	for (int i = 0, x = 1; x <= a; x *= t, ++ i)
	for (int j = 0, y = 1; y <= b; y *= t, ++ j)
	for (int k = 0, z = 1; z <= c; z *= t, ++ k)
		ans = (ans + 1LL * dfs(p - 1, a / x, b / y, c / z) * (i + j + k + 1) % mod) % mod;
	return f[p][code] = ans;
}

int main() {
	for (int i = 2; i <= 2000; ++ i) {
		bool flag = true;
		for (int j = 2; j * j <= i; ++ j)
			if (i % j == 0) {flag = false; break;}
		if (flag) Prime[++ cnt] = i;
	}
	int a, b, c;
	scanf("%d%d%d", &a, &b, &c);
	dfs(cnt, a, b, c);
	printf("%d", dfs(cnt, a, b, c));
	return 0;
}
posted @ 2021-11-03 21:58  zqs2020  阅读(36)  评论(0编辑  收藏  举报