数论——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
这个可以直接大力枚举 i j,做个前缀和就可以知道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(差点吓跑了)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值