暂无链接
数论题
【问题描述】
企鹅国数学家 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;
题解
从一眼看出要搞 之后,似乎没有什么实质进展,然而我有梦想啊!!!
呵呵, 分滚粗。
虽然看出了 的就是 数,然而感觉没有什么好的表示法,线筛 值得梦想也破灭了,唉我的数论还是太菜了。。。
为啥我想不到 来表示 数啊??? !
这样以后,就能列出初始的式子:
对于枚举约数的操作,我们可以替换成枚举倍数,这两个枚举是等价的,并且当因子为 数时,倍数也一定为 数,所以可以化简如下:
注意到 是可以用下底分块解决的,那么我们只要处理出 ,即 中 数的个数,这个当然可以线筛,不过只能过 的,实际上 数的个数还可以表示如下:
含义很简单,就是枚举所有非 数的平方的倍数,非 的平方必定是 数,平方的倍数肯定也是 数,但是一个数会被它的因数给算重,所以需要套个 去重,最后的形式如下:
注意,因为我们枚举的是非 数作为平方根( 数本身的 值为 ,直接被消掉了),所以枚举上界为 。
这样复杂度就对了,愉快的 。
代码
#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();}