杜教筛

前置芝士:莫比乌斯反演

略(莫比乌斯反演板子题,请)

前置芝士:积性函数

积性函数定义:如果已知一个函数为数论函数,且\(f(1)=1\),并且满足\(\forall gcd(p,q)=1,f(p⋅q)=f(p)⋅f(q)\),那么称这个函数为积性函数。

常见积性函数:这里就只提到我们需要用的几个了

\(\mu(n)\):莫比乌斯函数。学过莫比乌斯反演的应该都知道。

\(\phi(n)\):欧拉函数。不大于n且与n互质的正整数个数。

\(\epsilon(n)\):元函数。即\(\epsilon(n)=[n==1]\)。为什么叫元函数呢?等会会讲的。

\(I(n)\):恒等函数。即\(I(n)\equiv1\)

\(id(n)\):单位函数。即\(id(n)=n\)

注意:(积性函数∗积性函数)仍为积性函数

前置芝士:狄利克雷卷积

我们知道有两个多项式的卷积(就是乘积),而数论函数也是有卷积的。

狄利克雷卷积定义: 两个数论函数\(f\)\(g\)的卷积为\((f*g)(n)=\sum\limits_{d|n}f(d)g(\frac{n}{d})\)

很显然,狄利克雷卷积满足以下运算规律:

交换律\(f*g=g*f\)

结合律\((f*g)*h=f*(g*h)\)

分配律\((f+g)*h=f*h+g*h\)

现在我们来看为什么\(\epsilon(n)\)叫做元函数。
易证\(\epsilon*f=f\),即所有数论函数与元函数的卷积等于它本身。跟群环域中的单位元是一个概念,所以称之为元函数。
下面是几个经常用到的式子:

1:\(\mu*I=\epsilon\)\(\sum\limits_{d|n}\mu(d)=[n==1]\)

易证

2:\(\phi*I=id\)\(\sum\limits_{d|n}\phi(d)=n\)

易证

3:\(\phi=id*\mu\)\(\phi(n)=\sum\limits_{d|n}\mu(d)·\frac{n}{d}\)

证:2式左右两边同乘\(\mu\)得到\(\phi*I*\mu=id*\mu\).
\(\because\mu*I=\epsilon\)
\(\therefore\phi=id*\mu\)

4:\(\frac{\phi(n)}{n}=\sum\limits_{d|n}\frac{\mu(d)}{d}\)

证:由3式左右同除n可得

所以现在我们可以来学杜教筛了

杜教筛是在非线性时间内求出积性函数前缀和的一种算法,用来解决毒瘤题目。
具体的话先看步骤吧。
假设我们要求的是\(f(x)\)的前缀和

\(S(n)=\sum\limits_{i=1}^nf(i)\)

然后我们构造两个函数\(f\)\(g\)使得

\(h=f*g\)

\(h(x)=\sum\limits_{d|x}g(d)f(\frac{x}{d})\)

求个和

\(\sum\limits_{i=1}^nh(i)= \sum\limits_{i=1}^n\sum\limits_{d|n}g(d)f(\frac{i}{d})\)

把d提到外面

\(\sum\limits_{i=1}^nh(i)=\sum\limits_{d=1}^ng(d) \sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i)\)

\(\sum\limits_{i=1}^nh(i)=\sum\limits_{d=1}^ng(d)S(\lfloor\frac{i}{d}\rfloor)\)

把右边的第一项提出来得

$ \sum\limits_{i=1}^nh(i)=g(1)S(n)+ \sum\limits_{d=2}^ng(d)S(\lfloor\frac{i}{d}\rfloor)$

移项得

$ g(1)S(n)=\sum\limits_{i=1}^nh(i)- \sum\limits_{d=2}^ng(d)S(\lfloor\frac{i}{d}\rfloor)$

先线性筛一部分x比较小的\(f(x)\)(比如本题筛到\(5e6\))然后构造时找一个比较好求前缀和(最好是\((O(1)\))的\(h\),然后后面的用数论分块+递归解决(用map或Hash记忆化),可以达到\(O(n^\frac{2}{3})\)\(S(n)\)

然后来看本题,有没有觉得很简单了呢?

一、\(S(n)=\sum\limits_{i=1}^n\mu(i)\)

\(\because\mu*I=\epsilon\)
\(\therefore S(n)=1-\sum\limits_{d=2}^ng(d)S(\lfloor\frac{n}{d}\rfloor)\)

二、\(S(n)=\sum\limits_{i=1}^n\phi(i)\)

\(\because\phi*I=id\bigwedge\sum\limits_{i=1}^nid(i)=\frac{n(n-1)}{2}\)
\(\therefore S(n)=1-\sum\limits_{d=2}^ng(d)S(\lfloor\frac{n}{d}\rfloor)\)

然后就轻松地切掉了这道题

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define LL long long
#define Get getchar
using namespace std;
using namespace std::tr1;
inline int read() { register int x=0; register char ch=Get(); while(ch>'9'||ch<'0') ch=Get(); while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=Get(); return x; }
const int N=5e6;
int flag[N+1],prime[N+1],miu[N+1]={0,1};
LL phi[N+1]={0,1};
unordered_map<int,LL>ansmiu,ansphi;
LL MiuS(int n)
{
    if(n<=N) return miu[n];
    if(ansmiu.count(n)) return ansmiu[n];
    LL ans=1;
    for(int i=2,j;i<=n;i=j+1) j=n/(n/i),ans-=(j-i+1)*MiuS(n/i);
    return ansmiu[n]=ans;
}
LL PhiS(int n)
{
    if(n<=N) return phi[n];
    if(ansphi.count(n)) return ansphi[n];
    LL ans=(1ll*n*(n+1))>>1;
    for(int i=2,j;i<=n;i=j+1) j=n/(n/i),ans-=(j-i+1)*PhiS(n/i);
    return ansphi[n]=ans;
}
int main()
{
    register int tot=0;
    for(register int i=2,j;i<=N;++i)
    {
        if(!flag[i]) prime[++tot]=i,miu[i]=-1,phi[i]=i-1;
        for(j=1;j<=tot&&i*prime[j]<=N;++j)
        {
            flag[i*prime[j]]=1;
            if(!(i%prime[j])){miu[i*prime[j]]=0,phi[i*prime[j]]=phi[i]*prime[j];break;}
            miu[i*prime[j]]=-miu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
    for(register int i=2;i<=N;++i) miu[i]+=miu[i-1],phi[i]+=phi[i-1];
    register int T=read();
    while(T--)
    {
        register int n=read();
        printf("%lld %lld\n",PhiS(n),MiuS(n));
    }
    return 0;
}

转载于:https://www.cnblogs.com/cjoierShiina-Mashiro/p/10054797.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值