BZOJ传送门
题目描述
给出A,B,考虑所有满足 l ≤ a ≤ A l\leq a\leq A l≤a≤A, l ≤ b ≤ B l\leq b\leq B l≤b≤B,且不存在 n > 1 n>1 n>1使得 n 2 n^2 n2同时整除 a a a和 b b b的有序数,对 ( a , b ) (a,b) (a,b),求其 l c m ( a , b ) lcm(a,b) lcm(a,b)之和。答案模 2 30 2^{30} 230。
输入输出格式
输入格式
第一行一个整数T表示数据组数。接下来T行每行两个整数A,B表示一组数据。
T ≤ 2000 T ≤ 2000 T≤2000, A , B ≤ 4 × 1 0 6 A,B ≤ 4 × 10^6 A,B≤4×106
输出格式
对每组数据输出一行一个整数表示答案模 2 30 2^{30} 230的值
输入输出样例
输入样例#1
5
2 2
4 6
3 4
5 1
23333 33333
输出样例#1
7
148
48
15
451085813
解题分析
其实这道题不考虑那个因数没有平方数的条件的话和 **这道题**是一样的, 有这样一个式子:
∑
T
=
1
n
(
1
+
⌊
n
T
⌋
)
×
⌊
n
T
⌋
2
×
(
1
+
⌊
m
T
⌋
)
×
⌊
m
T
⌋
2
T
∑
k
∣
T
k
×
μ
(
k
)
\sum_{T=1}^{n}\frac{(1+\lfloor\frac{n}{T}\rfloor)\times\lfloor\frac{n}{T}\rfloor}{2}\times \frac{(1+\lfloor\frac{m}{T}\rfloor)\times\lfloor\frac{m}{T}\rfloor}{2} T\sum_{k|T}k\times \mu(k)
T=1∑n2(1+⌊Tn⌋)×⌊Tn⌋×2(1+⌊Tm⌋)×⌊Tm⌋Tk∣T∑k×μ(k)
然后我们发现我们枚举的
T
T
T似乎就是
g
c
d
(
i
,
j
)
gcd(i,j)
gcd(i,j)?? 于是
O
(
N
l
n
(
N
)
)
O(Nln(N))
O(Nln(N))预处理,
O
(
T
N
)
O(T\sqrt N)
O(TN)回答即可。
是否因数中含有完全平方数用 μ ( i ) \mu(i) μ(i)判定即可。
代码如下:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 4000500
const int MOD = 1 << 30;
#define ll long long
int miu[MX], pri[MX], pcnt, n, m, T;
ll F[MX];
bool npr[MX];
void get()
{
miu[1] = 1;
R int i, j, tar;
for (i = 2; i < MX; ++i)
{
if(!npr[i]) pri[++pcnt] = i, miu[i] = -1;
for (j = 1; j <= pcnt; ++j)
{
tar = i * pri[j];
if(tar > MX) break;
npr[tar] = true;
if(!(i % pri[j])) break;
miu[tar] = -miu[i];
}
}
for (i = 1; i < MX; ++i) if(miu[i])
{
for (j = i; j < MX; j += i)
(F[j] += miu[j / i] * j % MOD * (j / i) % MOD) %= MOD;
}
for (i = 1; i < MX; ++i) (F[i] += F[i - 1]) %= MOD;
}
IN int getsum(R int val) {return (val + 1) * val >> 1;}
int main(void)
{
scanf("%d", &T);
get();
ll ans;
W (T--)
{
scanf("%d%d", &n, &m);
if(n > m) std::swap(n, m); ans = 0;
for (R int lef = 1, rig; lef <= n; lef = rig + 1)
{
rig = std::min(n / (n / lef), m / (m / lef));
(ans += (F[rig] - F[lef - 1]) * getsum(n / lef) % MOD * getsum(m / lef) % MOD) %= MOD;
}
printf("%lld\n", (ans % MOD + MOD) % MOD);
}
}