P2398 GCD SUM
作者:互联网
P2398 GCD SUM
题目大意
\(\sum_{i=1}^n \sum_{j=1}^n \gcd(i, j)\)
分析
这个到是蛮好想的,我们推理一下。
\(\sum_{i=1}^n \sum_{j=1}^n \gcd(i, j) = \sum_{k=1}^n k*\sum_{x=1}^{\left \lfloor \frac{n}{k} \right \rfloor} \sum_{y=1}^{\left \lfloor \frac{n}{k} \right \rfloor} [gcd(i, j)]\)
接下来,我们的问题就转化为了,枚举k
,判断一个二维区间\(\{(x,y)|1 \leq x \leq \left \lfloor \frac{n}{k} \right \rfloor,1 \leq y \leq \left \lfloor \frac{n}{k} \right \rfloor\}\),其中有多少个数对其gcd(x,y)=1
,求出数量后*k,将所有k
的答案累加起来即为最后答案。
那如何判断一个二维区间
内互质的点对数量呢,这就是经典问题了。
先说结论,若二维区间是\(\{(x,y)|1 \leq x \leq n,1 \leq y \leq m\}\),则答案即为\(\sum_{i=1}^{n}\phi(i)+\sum_{i=1}^{m}\phi(i)-1\)。
扩展的话,即为区间的左下点不一定就是(1,1)
,但这个就不展开说了,因为就是类似于一个二维前缀和的东西,很简单。
这个结论也很好推理,给个提示,将矩形的左下角和右上角相连,接着分别从左边画横线,下边画竖线,就很容易理解了。
时间复杂度\(O(n)\)
Ac_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n;
int phi[N],Primes[N],cnt;
LL s[N];
bool st[N];
void get_eulers()
{
phi[1]=1;
for(int i=2;i<N;i++)
{
if(!st[i]) Primes[cnt++]=i,phi[i]=i-1;
for(int j=0;Primes[j]*i<N;j++)
{
st[Primes[j]*i]=1;
if(i%Primes[j]==0)
{
phi[Primes[j]*i]=phi[i]*Primes[j];
break;
}
else phi[i*Primes[j]]=phi[i]*(Primes[j]-1);
}
}
for(int i=1;i<N;i++) s[i] = s[i-1] + phi[i];
}
int main()
{
ios;
cin>>n;
get_eulers();
LL ans = 0;
for(int i=1;i<=n;i++){
LL t = n/i;
ans += (2*s[t]-1)*i;
}
cout<<ans<<endl;
return 0;
}
标签:lfloor,right,GCD,int,sum,rfloor,P2398,leq,SUM 来源: https://www.cnblogs.com/aitejiu/p/16661351.html