LibreOJ 6053 简单的函数(Min25筛)

 

 

题意如题……

又是一个典型的题。 

f(x)是一个积性函数,满足其f(p)和f(p^c)容易计算,所以显然可以用Min25筛来求和。具体来说套用Min25筛的模板即可。关于Min25筛,见博客:https://blog.csdn.net/u013534123/article/details/82596172

模板中需要替换的主要有几个地方。一是在初始化g(x,j)的时候,需要知道把所有出了1以外的正整数当作质数去计算的和是什么,以及1到第j个质数对应的f(i)的和。对于第一个,根据函数的定义,所有数字异或1再求和相当于是所有数字直接求和,那么答案就是n*(n+1)/2-1。对于第二个,由于质数只是需要算到sqrt(N)的级别,所以可以考虑初始筛素数的时候求一下。还有种方法,可以看到出了2以外,所以质数都是奇数,异或1之后会减一,所以可以考虑同时算一个质数的个数,然后求的时候减去之前的质数个数即可。这里运用了第二种方法。具体见代码:

#include<bits/stdc++.h>
#define mod 1000000007
#define LL long long
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define INF 0x3f3f3f3f
#define sf(x) scanf("%lld",&x)
#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;

const int N = 1e6 + 10;
const int inv = 5e8 +4;

LL p[N],w[N],g[N],h[N],ps[N],M,n;
int block,id[N],sz;
bool isp[N];

void init(int n)
{
    sz=0;
    for(int i=2;i<=n;i++)
    {
        if(!isp[i])p[++sz]=i,ps[sz]=(ps[sz-1]+i)%mod;
        for(int j=1;j<=sz&&p[j]*i<n;j++)
        {
            isp[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}

void sieve_g(LL n)
{
    M=0;
    for(LL i=1,last;i<=n;i=last+1)
    {
        LL len=n/i; last=n/len;
        w[++M]=len; g[M]=(w[M]-1)%mod;
        h[M]=w[M]%mod*((w[M]+1)%mod)%mod;
        h[M]=(h[M]*inv%mod-1+mod)%mod;
        if(len<=block) id[len]=M;
    }
    for(int i=1;i<=sz;i++)
        for(int j=1;j<=M&&p[i]*p[i]<=w[j];j++)
        {
            int op=w[j]/p[i]<=block?id[w[j]/p[i]]:n/(w[j]/p[i]);
            (g[j]-=g[op]-i+1)%=mod; (h[j]-=p[i]*(h[op]-ps[i-1])%mod)%=mod;
        }
}

LL S(LL x,LL y)
{
    LL k,res=0;
    if (x<=1||p[y]>x) return 0;
    if (x>block) k=n/x; else k=id[x];
    res=(h[k]-ps[y-1]-g[k]+y-1)%mod;
    if (y==1) res+=2;
    for(int i=y;i<=sz&&p[i]*p[i]<=x;i++)
        for(LL e=1,s=p[i]*p[i];s<=x;s*=p[i],e++)
            (res+=(p[i]^e)*S(x*p[i]/s,i+1)%mod+(p[i]^(e+1))%mod)%=mod;
    return res;
}

int main()
{
    sf(n);
    block=ceil(sqrt(n));
    init(n<=1e6?1e4:1e6); sieve_g(n);
    printf("%lld\n",(S(n,1)+1+mod)%mod);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值