P5325 【模板】Min_25筛

题意:定义积性函数f(x)f(x)f(x),且f(p^k)=p^k*(p^k−1)   (p是一个质数),求f(1)+f(2)+...f(n);

思路:板子题。重新打了一份装起来。

/*
定义积性函数f(x)f(x)f(x),且f(p^k)=p^k*(p^k−1)(p是一个质数),求f(1)+f(2)+...f(n);
n<=1e10; 2s;
*/
#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1000010;
const int Mod=1000000007,inv2=500000004,inv3=333333336;
struct min25 //很多部分需要long,不要搞错了
{
    ll p[maxn],sp1[maxn],sp2[maxn],N;
    ll g1[maxn],g2[maxn];int Sqr,ind1[maxn],ind2[maxn],num,tot;
    ll w[maxn]; bool vis[maxn];
    int MOD(int x){ if(x>=Mod) x-=Mod;return x; }
    void prime() //得到素数,sp1,sp2
    {
        rep(i,2,Sqr){
            if(!vis[i]){
                p[++num]=i;
                sp1[num]=MOD(sp1[num-1]+i);
                sp2[num]=(sp2[num-1]+1LL*i*i)%Mod;
            }
            for(int j=1;j<=num&&p[j]*i<=Sqr;j++){
                vis[p[j]*i]=1;
                if(i%p[j]==0) break;
            }
        }
    }
    void getind()
    {
        for(ll i=1;i<=N;i++){
            ll now=N/i,j=N/now,t=now%Mod;
            w[++tot]=now;
            g1[tot]=MOD(t*(t+1)/2%Mod+Mod-1); //因为我们全部都不考虑1。
            g2[tot]=MOD(t*(t+1)/2%Mod*(t*2+1)%Mod*inv3%Mod+Mod-1); //*2应该不需要%Mod
            if(now<=Sqr) ind1[now]=tot;
            else ind2[j]=tot;
            i=j;
        }
    }
    void getg1g2()
    {
        rep(i,1,num){ //注意w里面的东西是递减的,所以可以滚动
            for(int j=1;j<=tot&&p[i]<=w[j]/p[i];j++){
                ll now=w[j]/p[i];
                int k=now<=Sqr?ind1[now]:ind2[N/now];
                g1[j]=MOD(g1[j]-1LL*p[i]*(g1[k]-sp1[i-1]+Mod)%Mod+Mod);
                g2[j]=MOD(g2[j]-1LL*p[i]*p[i]%Mod*(g2[k]-sp2[i-1]+Mod)%Mod+Mod);
            }
        }
    }
    int S(ll x,int y)
    {
        if(x<=p[y]) return 0;
        ll k=x<=Sqr?ind1[x]:ind2[N/x];
        ll ans=(g2[k]-g1[k]+Mod-(sp2[y]-sp1[y])+Mod)%Mod;
        for(int i=y+1;i<=num&&p[i]*p[i]<=x;i++) {
            ll pe=p[i];
            for(int e=1;pe<=x;e++,pe=pe*p[i]){
               ll xx=pe%Mod;
               ans=(ans+xx*(xx-1)%Mod*(S(x/pe,i)+(e!=1)))%Mod;
               //这里的f(x)对应xx*(xx-1),其他函数把这里换了就行。
            }
         }
        return ans%Mod;
    }
    void solve(ll n)
    {
        N=n; Sqr=sqrt(N);
        prime(); //筛根号部分素数。
        getind();  //得到编号,以及一次前缀和,二次前缀和。
        getg1g2(); //得到素数1次前缀和,二次前缀和。
        printf("%d\n",MOD(S(N,0)+1));
    }
}T;
int main()
{
    ll N;
    scanf("%lld",&N);
    T.solve(N);
    return 0;
}

 

It is your time to fight!
posted @ 2019-09-11 18:07  nimphy  阅读(363)  评论(0编辑  收藏  举报