题面:51nod1188
emmm就是前一道题的升级版了。。。
首先建议去看一下我的前一篇题解:传送门。前一篇题解(就是“最大公约数之和”)是这篇题解的基础
首先一维变成了两维,我们还是可以按照原来的思路来做。
上一篇讲到求
∑ni=1gcd(i,n)
我们转成了
∑nx|nphi(n/x)∗x
,这题继续用
本题要求
∑ni=1∑i−1j=1gcd(i,j)
,那我们可以先转成
∑ni=1∑i−1x|iphi(i/x)∗x
我们再转化一下就成了
∑ni=2∑x∗y<=nx=1phi(i)∗x
可以发现这个式子和上面那个是等价的(注意
i
从2开始枚举,因为题目说
这个可以直接大力枚举
i
和
前一题是单点求phi,这题n比较小,直接大力欧拉筛出来就好了
最后离线询问的复杂度是
O(T)
,预处理复杂度
O(5∗106+???)
(据说是log我不会算),反正能过
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <ctime>
#include <map>
#include <queue>
#include <cstdlib>
#include <string>
#include <climits>
#include <set>
#include <vector>
#define int long long
using namespace std;
inline int read(){
int k=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
return k*f;
}
const int N=5e6;
int ans[N+10],pri[1000010],phi[N+10];
bool b[N+10];
inline void get(){
phi[1]=1;
for(int i=2;i<=N;i++){
if(!b[i])pri[++pri[0]]=i,phi[i]=i-1;
for(int j=1;j<=pri[0];j++){
if(i*pri[j]>N)break;
b[i*pri[j]]=1;
if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
else phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
signed main()
{
get();
for(int i=2;i<=N;i++)
for(int j=1;i*j<=N;j++)ans[i*j]+=phi[i]*j;
for(int i=2;i<=N;i++)ans[i]+=ans[i-1];
int T=read();
while(T--){
int x=read();
printf("%lld\n",ans[x]);
}
return 0;
}
其实这题我一眼是莫比乌斯反演QAQ(差点吓跑了)