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;
}