數論——51nod1188 最大公約數之和 V2

題面:51nod1188
emmm就是前一道題的升級版了。。。
首先建議去看一下我的前一篇題解:傳送門。前一篇題解(就是“最大公約數之和”)是這篇題解的基礎
首先一維變成了兩維,我們還是可以按照原來的思路來做。
上一篇講到求ni=1gcd(i,n) 我們轉成了nx|nphi(n/x)x ,這題繼續用
本題要求ni=1i1j=1gcd(i,j) ,那我們可以先轉成ni=1i1x|iphi(i/x)x
我們再轉化一下就成了ni=2xy<=nx=1phi(i)x
可以發現這個式子和上面那個是等價的(注意i 從2開始枚舉,因爲題目說ij 這樣就可以避免加上phi(1)x
這個可以直接大力枚舉ij ,做個前綴和就可以知道1~5e6之間的所有答案了
前一題是單點求phi,這題n比較小,直接大力歐拉篩出來就好了
最後離線詢問的複雜度是O(T) ,預處理複雜度O(5106+???) (據說是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(差點嚇跑了)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章