bzoj3529 SDOI2014数表

本文介绍了一个涉及数论和莫比乌斯反演的问题解决过程,包括预处理质数、莫比乌斯函数计算以及使用线段树进行区间修改查询等技巧。通过详细的算法实现和代码示例,帮助读者理解并掌握这一复杂问题的求解方法。

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

题意略。

题解:详见popoqqq大爷的题解。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
const int mx=100000;
int q,prime[N],bz[N],tot,mu[N];
int c[N];
struct node{int id;ll val;}f[N];
struct query
{
    int id,n,m,a;ll ans;
}s[N];
bool cmp1(query a,query b)
{
    return a.a<b.a;
}
bool cmp2(node a,node b)
{
    return a.val<b.val;
}
bool cmpid(query a,query b)
{
    return a.id<b.id;
}
int check(int x,int y)
{
    int s=0;
    while (x%y==0)
    {
        x/=y;
        s++;
    }
    return s;
}
ll ksm(int x,int y)
{
    if (!y) return 1;
    if (y==1) return x;
    ll w=ksm(x,y/2);
    w=(ll)w*w;
    if (y%2==1) w=(ll)(w*x)&inf;
    return w;
}
void pre(int n)
{
    mu[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (!bz[i])
        {
            prime[++tot]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=tot&&i*prime[j]<=n;j++)
        {
            bz[i*prime[j]]=1;;
            if (i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
    for (int i=1;i<=n;i++)
    {
        f[i].val=1;
        f[i].id=i;
    }
    for (int i=1;i<=tot;i++)
        for (int j=prime[i];j<=n;j+=prime[i])
        {
            int w=check(j,prime[i]);
            f[j].val=(ll)f[j].val*(ksm(prime[i],w+1)-1)/(prime[i]-1);
        }
}
void ins(int x,int y)
{
    while (x<=mx)
    {
        c[x]+=y;
        x+=x&(-x);
    }
}
ll find(int x)
{
    ll ans=0;
    while (x)
    {
        ans+=c[x];
        x-=x&(-x);
    }
    return ans;
}
void add(int x,int y)
{
    for (int i=x;i<=mx;i+=x)
        ins(i,mu[i/x]*y);
}
ll solve(int n,int m)
{
    ll ans=0,last;
    for (int i=1;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans+=(ll)(n/i)*(m/i)*(find(last)-find(i-1));
    }
    return ans;
}

int main()
{
    //("table.in","r",stdin),freopen("table.out","w",stdout);
    pre(mx);
    scanf("%d",&q);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&s[i].n,&s[i].m,&s[i].a);
        if (s[i].n>s[i].m) swap(s[i].n,s[i].m);
        s[i].id=i;
    }
    sort(s+1,s+q+1,cmp1);
    sort(f+1,f+mx+1,cmp2);
    int now=1,k=1;
    while (k<=q)
    {
        while (now<=mx&&f[now].val<=s[k].a)
        {
            add(f[now].id,f[now].val);
            now++;
        }
        while (k<=q&&(now>mx||s[k].a<f[now].val))
        {
            s[k].ans=solve(s[k].n,s[k].m);
            k++;
        }
    }
    sort(s+1,s+q+1,cmpid);
    for (int i=1;i<=q;i++)
        printf("%lld\n",s[i].ans&inf);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值