[2018.07.10 T3]数论题

本文介绍了一种数论问题的高效解法,该问题要求计算一个区间内所有整数的QQ值之和,其中QQ值定义为该数是QQ数的因数个数。文章详细解释了如何利用莫比乌斯函数进行优化,并给出了具体的实现代码。

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

暂无链接

数论题

【问题描述】

企鹅国数学家 QQ 潜心研究数论,终于发现了一个简单的数论问题!

一个 QQ 数定义为一个拥有一个大于 1 的完全平方数为因子的数字,一个数字的QQ 值定 义为这个数是 QQ 数的因数个数。

现在 QQ 想知道在[L,R]范围内,每个整数的 QQ 值之和是多少?

你只需要告诉他这个数字,他就可以给你宝贵的 10 分作为一个奖励!

【输入格式】

第一行两个整数 L, R 代表要求的数字范围;

【输出格式】

输出一个整数表示 L~R 里每个数字的 QQ 值之和。

【输入样例】

1 10

【输出样例】

4

【样例说明】

4 的QQ 值为 1,8 的QQ 值为 2,9 的QQ 值为 1。

【数据范围】

对于 10%的数据,R≤10^4;
对于另外 30%的数据,R≤10^6;
对于另外 10%的数据,R≤10^7;
对于 100%的数据,1≤L≤R≤10^9;

题解

从一眼看出要搞μμ之后,似乎没有什么实质进展,然而我有梦想啊!!!

After 3 hours...After 3 hours...

呵呵,4040分滚粗。

虽然看出了μ(i)=0μ(i)=0的就是QQQQ数,然而感觉没有什么好的表示法,线筛QQQQ值的梦想也破灭了,唉我的数论还是太菜了。。。

为啥我想不到1μ2(i)1−μ2(i)来表示QQQQ数啊???shtsh∗t

这样以后,就能列出初始的式子:

i=1np|i[1μ2(p)]∑i=1n∑p|i[1−μ2(p)]

对于枚举约数的操作,我们可以替换成枚举倍数,这两个枚举是等价的,并且当因子为QQQQ数时,倍数也一定为QQQQ数,所以可以化简如下:

i=1nni[1μ2(i)]∑i=1n⌊ni⌋[1−μ2(i)]

注意到ni⌊ni⌋是可以用下底分块解决的,那么我们只要处理出ni=1[1μ2(i)]∑i=1n[1−μ2(i)],即[1,n][1,n]QQQQ数的个数,这个当然可以线筛,不过只能过1e71e7的,实际上QQQQ数的个数还可以表示如下:

i=1n[1μ2(i)]=n22+n32+n52n62+...∑i=1n[1−μ2(i)]=⌊n22⌋+⌊n32⌋+⌊n52⌋−⌊n62⌋+...

含义很简单,就是枚举所有非QQQQ数的平方的倍数,非QQQQ的平方必定是QQQQ数,平方的倍数肯定也是QQQQ数,但是一个数会被它的因数给算重,所以需要套个μμ去重,最后的形式如下:

i=2nμ(i)ni2∑i=2nμ(i)⌊ni2⌋

注意,因为我们枚举的是非QQQQ数作为平方根(QQQQ数本身的μμ值为00,直接被消掉了),所以枚举上界为n

这样复杂度就对了,愉快的ACAC

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e6+5;
int miu[M],p[M],mx,le,ri;
bool isp[M];
void get()
{
    int i,j,t;
    miu[1]=1;
    for(i=2;i<=mx;++i)
    {
        if(!isp[i])p[++p[0]]=i,miu[i]=-1;
        for(j=1;j<=p[0];++j)
        {
            t=i*p[j];if(t>mx)break;
            isp[t]=1;
            if(i%p[j]==0){miu[t]=0;break;}
            miu[t]=-miu[i];
        }
    }
}
ll miu2(int x)
{
    int b=sqrt(x);ll ans=0;
    for(int i=2;i<=b;++i)ans-=miu[i]*(x/i/i);
    return ans;
}
ll calc(int x)
{
    ll ans=0,tmp,pre=0;
    for(int l=1,r;l<=x;l=r+1){r=x/(x/l);tmp=miu2(r);ans+=1ll*(tmp-pre)*(x/l);pre=tmp;}
    return ans;
}
void in(){scanf("%d%d",&le,&ri);}
void ac(){mx=sqrt(ri);get();printf("%lld",calc(ri)-calc(le-1));}
int main(){in();ac();}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值