题意:
求 (1000) 次
(n、m、p) 规模均为 (2e7)。
由于我蒻的一匹, 所以我看了题解。
题目的第一步是想到(或是证出来)一个结论, 如下:
怎么证这个结论呢?
首先就是将式子里的所有项都写成质因数分解的形式。
于是
(Leftarrow min(c_{i1}+c_{i2},c_{i1}+c_{i3},c_{i2}+c_{i3}) = min(c_{i1},c_{i2})+min(c_{i1},c_{i3})+min(c_{i2},c_{i3}) - min(c_{i1},c_{i2},c_{i3}))
似乎还没有规定 (c_{x1}) 、 (c_{x2}) 、 (c_{x3}) 分别对应 (i) 、 (j) 、 (k) 中的哪一个, 但是无论 (c_{x1}) 、 (c_{x2}) 、 (c_{x3}) 分别对应 (i) 、 (j) 、 (k) 中的哪一个,
(min(c_{i1}+c_{i2},c_{i1}+c_{i3},c_{i2}+c_{i3})) 的值
和 (min(c_{i1},c_{i2})+min(c_{i1},c_{i3})+min(c_{i2},c_{i3}) - min(c_{i1},c_{i2},c_{i3})) 的值
都不会改变(因为它们都是轮换式)。
故规定 (c_{i1} leq c_{i2} leq c_{i3}), 原等式转为
故结论成立。
所以
展开
把变量换得整齐点。
然后题目就转化为了分别求三个同样形式的式子。
那么怎么求(sum_{i=1}^nsum_{j=1}^m gcd^2(i,j))?
套路上场~~~
设(f(n) = n^2), 则
(sum_{i=1}^nsum_{j=1}^m gcd^2(i,j) = sum_{i=1}^nsum_{j=1}^m f(gcd(i,j)))
要找出(1 * g = f), 则(g = f * mu), 可以 (O(nlog log n)) 卷出来, 于是
分块求即可。
Luogu数据吸氧才能AC的丑陋代码
(其实函数 (g) 可以线性筛出来, 但是我不想写qwq)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 20000001;
const int mod = 1e9 + 7;
#define li long long
int pr_cnt, prime[maxn], v[maxn];
li g[maxn];
void euler(int n) {
g[1] = 1ll;
for(register int i=2; i<=n; ++i) {
if(!v[i]) {
v[prime[++pr_cnt] = i] = i;
g[i] = 1ll * i * i % mod;
}
for(int j=1; j<=pr_cnt; ++j) {
if(prime[j] > n/i || prime[j] > v[i]) break;
v[prime[j] * i] = prime[j];
g[prime[j] * i] = 1ll * g[i] * g[prime[j]] % mod;
}
}
for(int i=1; i<=pr_cnt; ++i)
for(int j=n/prime[i]; j>0; --j) {
g[prime[i] * j] -= g[j];
g[prime[i] * j] %= mod;
}
for(int i=1; i<=n; ++i) {
g[i] += g[i-1];
g[i] %= mod;
}
}
li calc(li n, li m) {
li len = min(n, m);
li res = 0ll;
for(register li i=1,j; i<=len; i=j+1) {
j = min(n/(n/i), m/(m/i));
j = min(j, len);
res += 1ll * (g[j]-g[i-1]) * (n/i) % mod * (m/i) % mod;
res %= mod;
}
return res;
}
int main()
{
euler(20000000);
int T; cin >> T; while(T--) {
li n,m,p;
scanf("%lld%lld%lld", &n,&m,&p);
li ans = 0ll;
ans = 1ll * p * calc(n,m) % mod;
ans += 1ll * n * calc(m,p) % mod;
ans %= mod;
ans += 1ll * m * calc(n,p) % mod;
ans = (ans%mod+mod)%mod;
cout << ans << '
';
}
return 0;
}