bzoj3529 [Sdoi2014]数表(莫比乌斯反演+树状数组)

本文介绍了一种利用线性素数筛处理sigma函数的方法,并提供了完整的C++代码实现。该方法的时间复杂度为O(T*logT+T*sqrt(n)*logn),适用于解决与数论中sigma函数相关的题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

%%%popoqqq大爷的题解:传送门
又掌握了线性素数筛处理sigma函数的技能。。。复杂度O(T*logT+T*sqrt(n)*logn)

#include <bits/stdc++.h>
#define ll long long
#define inf 0x7fffffff
#define pa pair<int,int>
#define N 100000
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int tst,mu[N+10],prime[N],tot=0,mnfac[N],c[N+10],ans[N+10];
pa f[N+10];
bool notprime[N+10];
struct que{
    int l,r,a,id;
}q[20010];
bool cmp(que x,que y){
    return x.a<y.a;
}
void Mobius(){
    notprime[1]=1;mu[1]=1;f[1].first=1;f[1].second=1;
    for(int i=2;i<=N;++i){
        f[i].second=i;
        if(!notprime[i]){
            prime[++tot]=i;mu[i]=-1;f[i].first=i+1;mnfac[i]=i;
        }for(int j=1;prime[j]*i<=N;++j){
            notprime[prime[j]*i]=1;
            if(i%prime[j]==0){
                mu[prime[j]*i]=0;mnfac[prime[j]*i]=mnfac[i]*prime[j];
                if(mnfac[prime[j]*i]==prime[j]*i) f[prime[j]*i].first=f[i].first+prime[j]*i;
                else f[prime[j]*i].first=f[i].first/f[mnfac[i]].first*f[mnfac[prime[j]*i]].first;break;
            }mu[prime[j]*i]=-mu[i];mnfac[prime[j]*i]=prime[j];
            f[prime[j]*i].first=f[i].first*f[prime[j]].first;
        }
    }for(int i=1;i<=N;++i) mu[i]+=mu[i-1];
}
void add(int x,int val){
    for(;x<=N;x+=x&(-x)) c[x]+=val;
}
int ask(int x){
    int res=0;
    for(;x>0;x-=x&(-x)) res+=c[x];return res;
}
int solve(int n,int m){
    int last,res=0;if(n>m) swap(n,m);
    for(int i=1;i<=n;i=last+1){
        last=min(n/(n/i),m/(m/i));
        res+=(n/i)*(m/i)*(ask(last)-ask(i-1));
    }return res&inf;
}
int main(){
//  freopen("a.in","r",stdin);
    tst=read();Mobius();sort(f+1,f+N+1);
    for(int i=1;i<=tst;++i){
        q[i].l=read();q[i].r=read();q[i].a=read();q[i].id=i;
    }sort(q+1,q+tst+1,cmp);
    for(int i=1,j=1;i<=tst;++i){
        while(j<=N&&f[j].first<=q[i].a){
            for(int k=1;k*f[j].second<=N;++k)
                add(k*f[j].second,f[j].first*(mu[k]-mu[k-1]));j++;
        }
        ans[q[i].id]=solve(q[i].l,q[i].r);
    }
    for(int i=1;i<=tst;++i) printf("%d\n",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值