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;//  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;
}
 

void getg0(ll n){//对每个n/i 求 g(n/i,0);  其中n/i映射到 ++m  

    //定义: g(x,p)=sum{i=1~x}[i的最小质因子>pri[p] or i是质数]g0(i) ,要求g0(p)是完全积性函数,不是的话要分开凑。 
    //g(n/i,0)代表 所有数当成质数带入  本来g0(p)=? 仅对质数有效
    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; 维护时省略第二维
    // 所以我们这个函数求的是  g(x,|P|)=sum{i=1~x}[i是质数]g0(i)  
    // g[1]=g(n/1,|P|) g[2]=g(n/2,|P|) ...g[m]=g(n/m,|P|) m是整数分块的上限
    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;                           //需要改 同上
        }
    //g[i]-g[i+1] 代表[n/(i+1),n/i]区间内的质数p的g0(p)的和
}
 
int main(){
    ll n;
    scanf("%lld",&n);
    Sqr=sqrt(n);init(Sqr);
    
    getg0(n);getgp(n);
    /*
    for(int i=1;i<=n;i++){
        printf("%d %d %d\n",n/i,i,g[i]);
    }*/

    ll ans1=S(n,1,n)+1;
    printf("%lld\n",(ans1+mod)%mod);
 
 
    system("pause");
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值