题目链接:点击这里
题目大意:
给定
n
,
m
n,m
n,m 求
∑
i
=
1
n
∑
j
=
1
m
2
gcd
(
i
,
j
)
−
1
\sum_{i=1}^n\sum_{j=1}^m2\gcd(i,j)-1
∑i=1n∑j=1m2gcd(i,j)−1
题目分析:
这个题可以通过反演求解,但我们换一种思路,从容斥原理的角度除法
设
f
x
f_x
fx 表示
gcd
(
i
,
j
)
=
x
\gcd(i,j)=x
gcd(i,j)=x 的数对个数,此时问题就转化成了求
∑
(
2
x
−
1
)
f
x
\sum (2x-1)f_x
∑(2x−1)fx ,直接求这个函数不太好求我们考虑间接求该函数值
设
g
x
g_x
gx 表示
x
x
x 是
(
i
,
j
)
(i,j)
(i,j) 公因数的数对个数,那么显然
g
x
=
(
n
/
x
)
×
(
m
/
x
)
g_x=(n/x)\times(m/x)
gx=(n/x)×(m/x)
有了
g
x
g_x
gx 后我们就可以通过容斥原理把
x
x
x 的
2
,
3
,
.
.
.
2,3,...
2,3,... 倍删掉,即
f
x
=
g
x
−
∑
i
=
2
i
x
≤
m
i
n
(
n
,
m
)
f
i
f_x=g_x-\sum_{i=2}^{ix\le min(n,m)}f_i
fx=gx−∑i=2ix≤min(n,m)fi
这样我们就可以倒着枚举求解
f
x
f_x
fx ,边求解边维护答案即可,时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) (调和级数)
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<string>
#define int long long
using namespace std;
const int maxn = 1e5+5;
int n,m,ans,f[maxn];
signed main()
{
cin>>n>>m;
for(int i = n;i;i--)
{
f[i] = (n/i)*(m/i);
for(int j = 2;i*j <= n;j++) f[i] -= f[i*j];
ans += (2*i-1)*f[i];
}
cout<<ans<<endl;
return 0;
}