[洛谷P3768]简单的数学题:线性筛+杜教筛+莫比乌斯反演

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN=10000005;
LL n,p,inv2,inv6,phi[MAXN];
int prm[MAXN>>3],cnt;
bool vis[MAXN];
map<LL,LL> f;
LL Qpow(LL x,LL y){
    LL ans=1,t=x;
    while(y){
        if(y&1) ans=(ans*t)%p;
        t=(t*t)%p;
        y>>=1;
    }
    return ans;
}
LL getinv(LL x){
    return Qpow(x,p-2);
}
void pre_process(){
    LL m=min(n,(LL)MAXN-5);
    phi[1]=1;
    for(int i=2;i<=m;i++){
        if(!vis[i]){
            prm[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt&&i*prm[j]<=m;j++){
            vis[i*prm[j]]=1;
            if(i%prm[j]==0){
                phi[i*prm[j]]=phi[i]*prm[j];
                break;
            }
            phi[i*prm[j]]=phi[i]*(prm[j]-1);
        }
    }
    for(int i=1;i<=m;i++)
        phi[i]=(phi[i]*i%p*i%p+phi[i-1])%p;
    inv2=getinv(2),inv6=getinv(6);
}
LL sum(LL x){
    return ((x+1)%p)*(x%p)%p*inv2%p;
}
LL sum2(LL x){
    return (x%p)*((x+1)%p)%p*((x*2+1)%p)%p*inv6%p;
}
LL solve(LL x){
    if(x<=MAXN-5) return phi[x];
    if(f.count(x)) return f[x];
    LL temp=sum(x);
    LL ans=temp*temp%p,nxti;
    for(LL i=2;i<=x;i=nxti){
        nxti=x/(x/i)+1;
        ans=(ans-(sum2(nxti-1)-sum2(i-1)+p)%p*solve(x/i)%p+p)%p;
    }
    return f[x]=ans;
}
int main(){
    scanf("%lld%lld",&p,&n);
    pre_process();
    LL ans=0,nxti;
    for(LL i=1;i<=n;i=nxti){
        nxti=n/(n/i)+1;
        LL temp=sum(n/i);
        ans=(ans+temp*temp%p*(solve(nxti-1)-solve(i-1)+p)%p)%p;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9367924.html