【模板】Min_25筛

【模板】Min_25筛(luogu)

Description

题目描述

定义积性函数 $f(x)$ ,且 $f(p^k)=p^k(p^k-1)$ ($p$ 是一个质数),求

$$\sum_{i=1}^n f(i)$$

对$10^9+7$取模。

输入格式

一行一个整数 $n$ 

Solution

洛谷题解里的大佬们讲得很清楚了

扫描二维码关注公众号,回复: 9467432 查看本文章

但蒟蒻还是花了好长时间才搞懂。。。awsl

程序运行时容易超精度,多%几下

Code

#include <cstdio>
#include <cstdlib>
#include <cmath>
#define ll long long
using namespace std;
const int N=1e6+10;
const ll P=1e9+7;
int vis[N],tot,cnt,ind1[N],ind2[N];
ll sp1[N],sp2[N],w[N],g1[N],n,g2[N],inv3=333333336,prime[N],sq;
void pre()
{
    for(int i=2;i<=sq;i++)//线性筛根号n内质数 
    {
        if(!vis[i])
        {
            prime[++tot]=i;
            sp1[tot]=(sp1[tot-1]+prime[tot])%P;
            sp2[tot]=(sp2[tot-1]+prime[tot]*prime[tot]%P)%P;
        }
        for(int j=1;j<=tot && prime[j]<=sq/i;j++)
        {
            vis[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}
ll S(ll x,int y)
{
    if(prime[y]>=x) return 0;
    ll k=x<=sq?ind1[x]:ind2[n/x];
    ll ans=(g2[k]-g1[k]-sp2[y]+sp1[y])%P;
    for(int i=y+1;i<=tot && prime[i]<=x/prime[i];i++)
    {
        ll now=prime[i];
        for(int j=1;now<=x;j++,now=now*prime[i])
        {
            ll xx=now%P;
            ans=(ans+xx*(xx-1)%P*(S(x/now,i)+(j!=1)))%P;
        }
    }
    return ans;
}
int main()
{
    scanf("%lld",&n);
    sq=sqrt(n);
    pre();
    for(ll l=1,r;l<=n;l=r+1)//处理可能用到的g 
    {
        r=n/(n/l);
        w[++cnt]=n/l;//离散可能用到的g,随着cnt增加w[cnt]依次减小 
        g1[cnt]=w[cnt]%P;
        //初始化g函数,即求g(i,0) 
        g2[cnt]=g1[cnt]*(g1[cnt]+1)/2%P*(2*g1[cnt]+1)%P*inv3%P-1;//求前(n/l)个数的平方和
        g1[cnt]=g1[cnt]*(g1[cnt]+1)/2%P-1;//求前(n/l)个数的和 
        if(n/l<=sq) ind1[n/l]=cnt;
        else ind2[n/(n/l)]=cnt;//哈希 
    }
    for(int i=1;i<=tot;i++)//dp,滚动优化掉g的第二维 
        for(int j=1;j<=cnt && prime[i]<=w[j]/prime[i];j++)
        {
            ll x=w[j]/prime[i];
            int k=(x<=sq)?ind1[x]:ind2[n/x];
            g1[j]=(g1[j]-prime[i]*(g1[k]-sp1[i-1])%P)%P;
            g2[j]=(g2[j]-prime[i]*prime[i]%P*(g2[k]-sp2[i-1])%P)%P;
        }
    printf("%lld\n",(S(n,0)+1+P)%P);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12378348.html