[2018.07.10 T3]数论题

暂无链接

数论题

【问题描述】

企鹅国数学家 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;

题解

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

A f t e r   3   h o u r s . . .

呵呵, 40 分滚粗。

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

为啥我想不到 1 μ 2 ( i ) 来表示 Q Q 数啊??? s h t

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

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

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

i = 1 n n i [ 1 μ 2 ( i ) ]

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

i = 1 n [ 1 μ 2 ( i ) ] = n 2 2 + n 3 2 + n 5 2 n 6 2 + . . .

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

i = 2 n μ ( i ) n i 2

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

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

代码
#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();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/81004779
T3
今日推荐