[bzoj3944]Sum

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 2500005
map <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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值