洛谷 P3601 签到题

https://www.luogu.org/problemnew/show/P3601

一道关于欧拉函数的题。

读完题目以后我们知道所谓的$aindao(x)=x- phi (x) $。

对于x小的情况下我们当然可以用 枚举因子或者线型筛求得,然而x打了以后就数组装不下了。

注意区间大小,我们完全可以只求这一部分区间内的x的$ phi (x) $,数字移一下位置就好了。

然而求没一个数的欧拉函数值时我们只用到了,小于等于$sqrt x$的质因子(就想线性筛一样),所以我们只需要晒出小于$sqrt r$的素数是什么,然后了枚举区间中每一个数的倍数然后用公式进行不断地更新就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define LL long long
#define mod 666623333
LL prime[1000006],vis[1000006],tot,cnt,phi[1000006];
LL l,r,ans;
void prepare()
{    
    for(int i=2;i<=1000000;i++)
    {
        if(!vis[i])prime[++tot]=i;
        for(int j=1;j<=tot&&prime[j]*i<=1000000;j++)
        {
            vis[prime[j]*i]=1;
            if(i%prime[j]==0)
            {
//                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
//            else phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
}
LL A[1000006],B[1000006]; 
int main()
{
    prepare();
    scanf("%lld%lld",&l,&r);
    for(LL i=0;i<=r-l+1;i++)phi[i]=B[i]=i+l-1;
    for(LL i=1;i<=tot&&prime[i]*prime[i]<=r;i++)
    {
        LL lb=prime[i]*(l/prime[i]),rb=prime[i]*(r/prime[i]);
//        cout<< lb<<" "<<rb<<"
";
        for(LL j=lb;j<=rb;j+=prime[i])
        {
            if(j>=l)
            {
                phi[j-l+1]=phi[j-l+1]/prime[i]*(prime[i]-1);
                while(B[j-l+1]%prime[i]==0)B[j-l+1]/=prime[i];
            }
        }
    }

    for(int i=1;i<=r-l+1;i++)
    {
        if(B[i]>1)phi[i]=phi[i]/B[i]*(B[i]-1);    //剩下一堆大质数了。 
        ans+=l+i-1-phi[i];ans%=mod;
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/rmy020718/p/9766260.html