Mobius反演

本文深入解析了数论算法中关于完全平方数的问题处理方法及数表的求解技巧,介绍了如何利用质因数分解和莫比乌斯函数优化计算过程。

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

2440: [中山市选2011]完全平方数
最直观的想法是容斥,x-x/(pi)^2+x/(pi*pj)^2……
但是最坏情况下可能有O(2^p) ,虽然很快就会超过x,还是很快的,
换一种方法来分析,我们只要某些质数的乘积来算,那么mu[i]!=0的i就是符合要求的数字,而其他的+-号由于mu[i]相同,所以直接ans+=x/(i*i)*mu[i]即可.

3529: [Sdoi2014]数表
这道题目有点难度
http://www.cnblogs.com/Bleacher/p/6773761.html
贴一发lzw题解
我只要讲讲没讲清楚的
首先如何求F(x):x的约数和
我记录了val[x]:x的最小质数的乘积,即p1^c1
sum[x]:p1^0+p1^1+p1^2+……p1^c1
这这样就可以推导出F(x)了
然后 f[x]=diF[d]u[x/d]
这个我们可以枚举倍数暴力求,也就O(nlgn)
现在有了限制a,我们离线将a,f排序,每次线扫把符合条件的插入树状数组,然后照常
时间复杂度:插入O(nlogn^2) 查询 O(Qlgn n )

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100000+1000;
int sum[N],mu[N],val[N],F[N],prime[N],c[N],ans[N],tot;
bool flag[N];

struct node{
    int f,id;
    bool operator < (const node &a) const
    {return f<a.f;}
}f[N];
struct Que{
    int n,m,a,id;
    bool operator < (const Que &b) const
    {return a<b.a;}
}a[20010];


void prepare()
{
    mu[1]=F[1]=1;
    for (int i=2;i<N;i++)
    {
        if (!flag[i])
        {
            prime[++tot]=i;
            mu[i]=-1;
            val[i]=i;
            F[i]=sum[i]=i+1;
        }
        for (int j=1;j<=tot;j++)
        {
            int p=prime[j];
            if (p*i>=N) break;
            flag[p*i]=true;
            if (i%p==0)
            {
                val[p*i]=val[i]*p;
                sum[p*i]=sum[i]+val[p*i];
                F[p*i]=F[i]/sum[i]*sum[i*p];
                break;
            }
            mu[i*p]=-mu[i];
            val[p*i]=p;
            sum[p*i]=p+1;
            F[p*i]=F[i]*(p+1);
        }
    }
    for (int i=1;i<N;i++) f[i]=(node){F[i],i};
}
void add(int x,int v)
{
    for (int i=x;i<N;i+=i&(-i)) c[i]+=v;
}
int query(int x)
{
    int ret=0;
    for (int i=x;i;i-=i&(-i)) ret+=c[i];
    return ret;
}
void insert(int x,int d)
{
    for (int i=d;i<N;i+=d)
        add(i,x*mu[i/d]);
}
int main()
{
    prepare();
    int T;
    scanf("%d",&T);
    for (int i=1;i<=T;i++)
        scanf("%d%d%d",&a[i].n,&a[i].m,&a[i].a),a[i].id=i;
    sort(f+1,f+N);
    sort(a+1,a+1+T);
    int pos=1;
    for (int i=1;i<=T;i++)
    {
        while (pos<N && f[pos].f<=a[i].a)
            insert(f[pos].f,f[pos].id),pos++;
        int n=a[i].n,m=a[i].m;
        if (n>m) swap(n,m);
        for (int j=1,last=0;j<=n;j=last+1)
        {
            last=min(n/(n/j),m/(m/j));
            ans[a[i].id]+=(n/j)*(m/j)*(query(last)-query(j-1));
        }
    }
    for (int i=1;i<=T;++i)
        printf("%d\n",(ans[i]<0?ans[i]+2147483648:ans[i])); 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值