[bzoj3944]Sum

来源:互联网 发布:苹果电脑允许安装软件 编辑:程序博客网 时间:2024/06/08 02:47

Orz w_yqts
Orz xudyh
杜教筛模板题
给定积性函数f(x)
函数s(x)为f(x)的前缀和
f(x)满足Σf(d)=g(x),d为x的约数,g(x)的前缀和可以在较短时间内算出.
求s(n)

这里写图片描述
从枚举约数到枚举倍数,将离散变为连续…
上面的j枚举的就是倍数,i是当前倍数可以支持的约数,不难发现,可以支持的约数是连续的.
预处理前n^(2/3),后面直接用map记忆化…
大概是O(n^(2/3))的吧…
PS:这道题我预处理前2500000就过了,别的都TLE了…
这里写图片描述

#include <bits/stdc++.h>using namespace std;#define ll long long#define N 2500005map <int,ll> f1,f2;ll phi[N],miu[N];int pn,pr[N],flag[N];inline void init(){    flag[1]=phi[1]=miu[1]=1LL;    pn=0;    for (int i=2;i<N;++i)    {        if (!flag[i]) pr[++pn]=i,phi[i]=i-1,miu[i]=-1;        for (int j=1;j<=pn && pr[j]*i<N;++j)        {            flag[i*pr[j]]=1;            if (i%pr[j]==0) {phi[i*pr[j]]=phi[i]*pr[j];miu[i*pr[j]]=0;break;}            phi[i*pr[j]]=phi[i]*(pr[j]-1);miu[i*pr[j]]=-miu[i];        }    }    for (int i=1;i<N;++i) phi[i]+=phi[i-1],miu[i]+=miu[i-1];}inline ll calcphi(ll n){    if (n<N) return phi[n];    if (f1[n]) return f1[n];    ll res=(ll)(n+1)*n>>1;    for (ll i=2,pos;i<=n;i=pos+1)    {        pos=n/(n/i);        res-=calcphi(n/i)*(pos-i+1);    }    return f1[n]=res;}inline ll calcmiu(ll n){    if (n<N) return miu[n];    if (f2[n]) return f2[n];    ll res=1LL;    for (ll i=2,pos;i<=n;i=pos+1)    {        pos=n/(n/i);        res-=calcmiu(n/i)*(pos-i+1);    }    return f2[n]=res;}void solve(){    int n;    scanf("%d",&n);    printf("%lld %lld\n",calcphi(n),calcmiu(n));}int main(){    init();    int T;    cin>>T;    while (T--) solve();    return 0;}
原创粉丝点击