【莫比乌斯反演】51Nod 1678 lyk与gcd

博客介绍了如何利用莫比乌斯反演解决51Nod上的题目1678 lyk与gcd。通过推导,博主展示了在维护f(d)和进行询问时可以达到O(n√n)的复杂度,给出了示例程序。

题面在这里

一开始不会做,在Lynstery大佬的点拨下秒懂了……

首先推柿子:

j=1n[gcd(i,j)=1]ajj=1najd|(i,j)μ(d)d|iμ(d)d|jaj

d|jaj 看做是关于d的函数 f(d)

因为 aj 只对 j 的因子有贡献,修改时暴力维护f(d) O(n)

询问也一样,枚举 i 的因子d,也可以 O(n) 得到答案

总复杂度 O(nn)

示例程序:

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=100005,N=maxn-5;
int n,q,a[maxn],mu[maxn],p[maxn];
ll f[maxn];
vector<int> fac[maxn];
bool vis[maxn];
void prepare(){
    mu[1]=1;
    for (int i=2;i<=N;i++){
        if (!vis[i]) p[++p[0]]=i,mu[i]=-1;
        for (int j=1;j<=p[0]&&i*p[j]<=N;j++){
            vis[i*p[j]]=1;
            if (i%p[j]==0) {mu[i*p[j]]=0;break;}
             else mu[i*p[j]]=-mu[i];
        }
    }
    for (int i=1;i<=N;i++)
     for (int j=1;i*j<=N;j++) fac[i*j].push_back(i);
    for (int i=1;i<=n;i++)
     for (int j=0;j<fac[i].size();j++)
      f[fac[i][j]]+=a[i];
}
int main(){
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    prepare();
    while (q--){
        int c;scanf("%d",&c);
        if (c==1){
            int i,b;scanf("%d%d",&i,&b);
            for (int j=0;j<fac[i].size();j++)
             f[fac[i][j]]+=b-a[i];
            a[i]=b;
        }else{
            int i;scanf("%d",&i);ll ans=0;
            for (int j=0;j<fac[i].size();j++)
             ans+=mu[fac[i][j]]*f[fac[i][j]];
            printf("%lld\n",ans);
        }
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值