[luogu3601]签到题

[luogu3601]签到题

luogu
\[\sum_{i=l}^ri-\phi(i)\]
一个朴素的想法是枚举l~r,根号求\(\phi\),显然这样是\((r-l)\sqrt r\),时间无法承受
考虑怎么优化求\(\phi\)的时间,
我们知道对于一个数x,超过\(\sqrt x\)的质因子最多只有一个
我们考虑对[l,r]的数开vector记录质因子
我们可以线筛求出\(\sqrt r\)以内的质数,枚举它们的倍数放到相应的[l,r]的vector中
再枚举l~r求\(\phi\)
这样时间和空间都是\((r-l)logr\)

#define ll long long
#include<bits/stdc++.h>
using namespace std;
const int _=1000005;
int mx,cnt,p[100000];
ll l,r,ans;
bool vis[_];
vector<int>v[_];
int main(){
    cin>>l>>r;mx=sqrt(r);
    for(int i=2;i<=mx;i++){
        if(!vis[i])p[++cnt]=i;
        for(int j=1;j<=cnt&&p[j]*i<=mx;j++){
            vis[p[j]*i]=1;if(i%p[j]==0)break;
        }
    }
    for(int i=1;i<=cnt;i++){
        ll k=ceil(1.0*l/p[i])*p[i];
        while(k<=r)v[k-l].push_back(p[i]),k+=p[i];
    }
    for(int i=0;i<=r-l;i++){
        ll x=i+l,phi=i+l;
        for(int j=0,sz=v[i].size();j<sz;j++){
            int k=v[i][j];
            phi/=k;phi*=k-1;
            while(x%k==0)x/=k;
        }
        if(x>1)phi/=x,phi*=x-1;
        ans=(ans+i+l-phi)%666623333;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdzwyq/p/9931810.html