其他分享
首页 > 其他分享> > 51nod1239 min25筛 欧拉函数前缀和

51nod1239 min25筛 欧拉函数前缀和

作者:互联网

题意:n<=1e10 求phi(i)的前缀和

思路:定义g(n,j)=sum{i=1~n}g0(i)*[i的最小质因子>第j个质数 or i是质数]

考虑埃氏筛里每筛掉一个最小质因子带来的贡献来递推求g(n/i,j),滚动滚掉j那一维

要点就几个吧 phi(p)=p-1

所以将其分为g0(p)=p  h0(p)=1 两个完全积性函数来求每个g(n/i,|p|)跟g(n/i,0)

phi(p^k)=p^(k)-p^(k-1),接下来就是套板子的事情了

//min25筛求f前缀和 
//要求:积性函数+f(p)是多项式(或者是完全积性函数的和 )+ f(p^c)非常好求
//51nod 1239 欧拉函数前缀和 
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
const int N = 1e6+5;
const ll mod = 1e9+7;
ll Sqr,isp[N],pri[N],sump[N],tot,m,id1[N],id2[N],g[N],h[N];
ll w[N];
void init(int n){//线筛预处理质数 与质数的前缀和(f(p)的前缀和)
    isp[1]=1;
    for (int i=2;i<=n;++i){
        if (!isp[i]) pri[++tot]=i,sump[tot]=1ll*(sump[tot-1]+i)%mod;
        for (int j=1;i*pri[j]<=n;++j){
            isp[i*pri[j]]=1;
            if (i%pri[j]==0) break;
        }
    }
}

ll qmod(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b=b>>1;
    }return res;
}
int fpc(int p,int c){//f(p^c)
    
    return (qmod(p,c)-qmod(p,c-1)+mod)%mod;
}

int S(ll x,int y,ll n){//S(x,y)=sum{i=1~x}[i的最小质因子>=pri[y] ]*f(i);
    if (x<=1||pri[y]>x) return 0;
    int k=(x<=Sqr)?id1[x]:id2[n/x];
    ll res=(1ll*g[k]-h[k]-sump[y-1]+y-1);(res=res+mod)%mod;//A. res= g(n,|P|)-sum_{i=1~j}f(Pi),需要改
    //if (y==1) res+=2;//特判 f(2)=f(p)+2 其他题可删
    for (int i=y;i<=tot&&1ll*pri[i]*pri[i]<=x;++i){
        ll p1=pri[i],p2=1ll*pri[i]*pri[i];
        for (int e=1;p2<=x;++e,p1=p2,p2*=pri[i])
            (res+=(1ll*S(x/p1,i+1,n)*fpc(pri[i],e)%mod+fpc(pri[i],(e+1))))%=mod;//pri[i]^e 是f(pri[i]^e)的值,需要改
    }
    return res%mod;
}

//定义: g(x,p)=sum{i=1~x}[i的最小质因子>pri[p] or i是质数]g0(i) ,要求g0是完全积性函数,不是的话要分开求。 后面在A处会合并
void getg0(ll n){//对每个n/i 求 g(n/i,0);  其中n/i映射到 ++m
    memset(h,0,sizeof(h));
    m=0;Sqr=sqrt(n);
    for (ll i=1,j;i<=n;i=j+1){
        j=n/(n/i);w[++m]=n/i;//整数分块 ; 下标映射 ;
        if (w[m]<=Sqr) id1[w[m]]=m;
        else id2[n/w[m]]=m;

        //合数也当成质数求和 h0(i)=1 g0(i)=i 
        h[m]=(w[m]-1);
        g[m]=((w[m]+2)%mod)*((w[m]-1)%mod)%mod;
        if (g[m]&1) g[m]+=mod;g[m]/=2;
    }
}

void getgp(ll n){//对每个n/i 求g(n/i,|P|) h(n/i,|P|) 之前n/i映射到w[i]=n/i; 

    // g(x,p)=sum{i=1~x}[i的最小质因子>p or i是质数]g0(i)  ,其中g0(i)=i; 维护时省略第二维   f(p)=g0(p)-h0(p)凑完全积性 
    // h(x,p)=sum{i=1~x}[i的最小质因子>p or i是质数]h0(i)  ,其中h0(i)=1; 维护时省略第二维
    for (int j=1;j<=tot;++j)
        for (int i=1;i<=m&&1ll*pri[j]*pri[j]<=w[i];++i){
            int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];//不用改

            g[i]=(g[i]-1ll*pri[j]*(g[k]-sump[j-1])%mod)%mod;g[i]=(g[i]+mod)%mod;//需要改 g(n,j)=g(n,j-1) -g0(pri[j])*[ (]g(k,j-1)-sum_{i=1~j-1}g0(pri[i]) ];
            h[i]=(h[i]-h[k]+j-1);h[i]=(h[i]+mod)%mod;                           //需要改 同上
        }
}

int main(){
    ll n;
    scanf("%lld",&n);
    Sqr=sqrt(n);init(Sqr);
    
    getg0(n);getgp(n);
    ll ans1=S(n,1,n)+1;
    printf("%lld\n",(ans1+mod)%mod);


    system("pause");
    return 0;
}

 

标签:前缀,g0,int,min25,积性,质数,51nod1239,ll
来源: https://blog.csdn.net/animalcoder/article/details/100154359