題面:51nod1188
emmm就是前一道題的升級版了。。。
首先建議去看一下我的前一篇題解:傳送門。前一篇題解(就是“最大公約數之和”)是這篇題解的基礎
首先一維變成了兩維,我們還是可以按照原來的思路來做。
上一篇講到求
本題要求
我們再轉化一下就成了
可以發現這個式子和上面那個是等價的(注意
這個可以直接大力枚舉
前一題是單點求phi,這題n比較小,直接大力歐拉篩出來就好了
最後離線詢問的複雜度是
#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(差點嚇跑了)