【洛谷5438】【XR-2】记忆(数论)

【洛谷5438】【XR-2】记忆(数论)

题面

洛谷

题解

很好的一道题目。
我们首先把所有数的每个质因子的出现次数模二,也就是把最大的完全平方因子给除掉。然后剩下部分一样的就可以产生\(1\)的贡献,所以答案就是\(r-l+1\)减去除掉完全平方因子之后不同的数的个数。
那么如果\(l=1\),答案就是不含完全平方数因子的数的个数,也就是\(\sum_{i=1}^r \mu(i)^2\),这个可以容斥在\(O(\sqrt r)\)的复杂度下得到答案。
现在我们还是一样的枚举除掉某个完全平方因子之后数的个数,那么对于\(k^2\)而言,除掉之后产生的数是\(\displaystyle (\frac{l-1}{k^2},\frac{r}{k^2}]\),于是我们要计算的就是区间内不含其他完全平方因子的数的个数。
最后所有区间取个并就可以计算答案了。
对于区间内不含完全平方因子的数的个数,提前预处理出一部分的答案,剩下的部分直接容斥就好了。
复杂度不太会分析。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 10000010
ll l,r,ans;
bool zs[MAX];
int pri[MAX],tot,mu[MAX],smu[MAX],ssmu[MAX];
void Sieve(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!zs[i])pri[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*pri[j]<=n;++j)
        {
            zs[i*pri[j]]=true;
            if(i%pri[j]==0)break;
            mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;++i)smu[i]=smu[i-1]+mu[i];
    for(int i=1;i<=n;++i)ssmu[i]=ssmu[i-1]+(mu[i]!=0);
}
ll Calc(ll n)
{
    if(n<MAX)return n-ssmu[n];
    ll ret=0,blk=sqrt(n);
    for(ll i=2,j;i<=blk;i=j+1)
    {
        j=min(blk,(ll)sqrt(n/(n/i/i)));
        ret-=n/i/i*(smu[j]-smu[i-1]);
    }
    return ret;
}
int main()
{
    scanf("%lld%lld",&l,&r);Sieve(MAX-1);
    ans=Calc(r)-Calc(l-1);
    for(ll i=2,lst=l-1;i*i<=r;++i)
    {
        ll L=(l-1)/(i*i),R=min(lst,r/(i*i));
        if(L<R)ans-=R-L-Calc(R)+Calc(L);
        lst=L;
    }
    printf("%lld\n",ans);
    return 0;
}
上一篇:【洛谷5437】【XR-2】约定(拉格朗日插值)


下一篇:【2019西安邀请赛J】And And And(树链贡献)