入门杜教筛啦。

http://blog.csdn.net/skywalkert/article/details/50500009(好文!)

可以在$O(N^{\frac{2}{3}})或O(N^{\frac{3}{4}})$的复杂度内解决求某些数论函数f(n)(或f的前缀和S(n)$)的值。

先来看看原理是什么。(接下来推导如何求数论函数f(n)的前缀和S(n))


现在有两个数论函数$f( )和g( )$

(同时定义f的前缀和函数$S(n)=\sum_{i=1}^{n}f(i)$)

有狄利克雷乘积可知:

$$f*g(n)=\sum_{i|n}f(\frac{n}{i})g(i)\quad(=\sum_{i|n}f(i)g(\frac{n}{i}))$$

那么,则有如下结论:

$$\sum_{n=1}^{N}f*g(n)=\sum_{i=1}^{N}g(i)S(\lfloor \frac{N}{i} \rfloor)$$

证明如下:

$$\begin{align*}
\sum_{n=1}^{N}f*g(n)&=\sum_{n=1}^{N}\sum_{i|n}f(\frac{n}{i})g(i)\\
&=\sum_{i=1}^{N}g(i)\sum_{i=1}^{\lfloor \frac{N}{i} \rfloor}f(i)\\
&=\sum_{i=1}^{N}g(i)S(\lfloor \frac{N}{i} \rfloor)
\end{align*}$$

然后把右边和式里的$g(1)S(N)$那一项提出来得到:

$$g(1)S(N)=\sum_{n=1}^{N}f*g(n)-\sum_{i=2}^{N}g(i)S(\lfloor \frac{N}{i} \rfloor)$$

通常令数论函数$g(n)=I(n)=1$(恒等函数$l(n)=1$,完全积性)

到目前为止,上式就是我们进行杜教筛的基础了。

因为左边的S(N)就是答案,而右边同时又可以用分块的方式计算。

不少刚刚入门的同学会有一个疑问,等式右边的后半部分确实可以分块计算,但是前半部分怎么办呢?

其实,一般前面的$\sum_{n=1}^{N}f*g(n)$都是可以O(1)计算出来的。

下面来看两个例子:


(一)、求莫比乌斯函数$\mu(n)$的前缀和函数$S(n),n \leq 10^9$

首先添加一个辅助函数g(n)=l(n)=1,

然后重复上面的过程,可以得到

$$g(1)S(N)=\sum_{n=1}^{N}\mu*g(n)-\sum_{i=2}^{N}g(i)S(\lfloor \frac{N}{i} \rfloor)$$

$$S(N)=\sum_{n=1}^{N}\mu*g(n)-\sum_{i=2}^{N}S(\lfloor \frac{N}{i} \rfloor)$$

现在来看看$\sum_{n=1}^{N}\mu*g(n)$怎么求:

$$\begin{aligned}
\sum_{n=1}^{N}\mu*g(n)&=\sum_{n=1}^{N}\sum_{i|n}\mu(i)g(\frac{n}{i})\\
&=\sum_{n=1}^{N}\sum_{i|n}\mu(i)\\
&=\sum_{n=1}^{N}[n==1]\\
&=1
\end{aligned}$$

上面的化简用到了刚刚学莫比乌斯函数时的一个结论:

$$\sum_{i|n}\mu(i)=[n==1]$$

到此,我们得到:

$$S(N)=1-\sum_{i=2}^{N}S(\lfloor \frac{N}{i} \rfloor)$$

实现方式是分块计算+记忆化递归处理(用map或者hash表记忆化)


(二). 求欧拉函数$\phi(n)$的前缀和函数$S(n),n \leq 10^9$

同样地,添加一个辅助函数g(n)=l(n)=1,

然后重复上面的过程,可以得到

$$g(1)S(N)=\sum_{n=1}^{N}\phi*g(n)-\sum_{i=2}^{N}g(i)S(\lfloor \frac{N}{i} \rfloor)$$

$$S(N)=\sum_{n=1}^{N}\phi*g(n)-\sum_{i=2}^{N}S(\lfloor \frac{N}{i} \rfloor)$$

$\sum_{n=1}^{N}\phi*g(n)$又怎样求呢:

$$\begin{aligned}
\sum_{n=1}^{N}\phi*g(n)&=\sum_{n=1}^{N}\sum_{i|n}\phi(i)g(\frac{n}{i})\\
&=\sum_{n=1}^{N}\sum_{i|n}\phi(i)\\
&=\sum_{n=1}^{N}n\\
&=\frac{(1+n)n}{2}
\end{aligned}$$

上面的化简用到了这样一个结论:

$$\sum_{i|n}\phi(i)=n$$

所以我们得到:

$$S(N)=\frac{(1+n)n}{2}-\sum_{i=2}^{N}S(\lfloor \frac{N}{i} \rfloor)$$

这个同样是实现方式是分块计算+记忆化递归处理(用map或者hash表记忆化)


下面是代码具体实现:

关于时间复杂度的分析不太会。记了一下结论。

通常不做任何处理,就直接杜教筛的话(分块计算+记忆化递归处理),复杂度是$O(N^{\frac{3}{4}})$

但是如果预处理出前$N^{\frac{2}{3}}$个前缀和,那么总的复杂度就可以降到$O(N^{\frac{2}{3}})$

BZOJ 3944: Sum,杜教筛入门题。

多个询问,给出N,求$\sum_{n=1}^{N}\mu(n)$和$\sum_{n=1}^{N}\phi(n)$

也就是求上面的两个例子。

这里直接给出代码,用的是预处理前$N^{\frac{2}{3}}$个前缀和+hash表进行记忆化。

复杂度$O(N^{\frac{2}{3}})$

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define DJM 1664510
//#define DJM 10
#define ll long long
using namespace std;
ll phi[DJM+50],mu[DJM+50];
struct Pii{
int x; ll a,b;
Pii(int _x=0,ll _a=0,ll _b=0):x(_x),a(_a),b(_b){}
}nl;
struct Hash_Table{//
#define hmod 1425367
int nxt[hmod],head[hmod],hnt;
Pii info[hmod];
Hash_Table(){hnt=2;}
void Push(Pii rtm){
static int u; u=rtm.x%hmod;
info[hnt]=rtm; nxt[hnt]=head[u]; head[u]=hnt++;
}
Pii Find(int x){
static int u; u=x%hmod;
for(int i=head[u];i;i=nxt[i]) if(info[i].x==x) return info[i];
return nl;
}
}H;
void Sieve(){
static bool np[DJM+50];
static int prime[DJM+50],pnt;
phi[1]=mu[1]=1;
for(int i=2;i<=DJM;i++){
if(!np[i]) prime[++pnt]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=pnt&&i<=DJM/prime[j];j++){
np[i*prime[j]]=1;
if(i%prime[j]){mu[i*prime[j]]=-mu[i]; phi[i*prime[j]]=phi[i]*phi[prime[j]];}
else{phi[i*prime[j]]=phi[i]*prime[j]; break;}
}
}
for(int i=2;i<=DJM;i++) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
Pii DJ_Sieve(int x){
if(x<=DJM) return Pii(x,mu[x],phi[x]);
if(H.Find(x).x) return H.Find(x);
Pii tmp,now=Pii(x,1,(1ll+x)*x/2);
for(ll i=2,last;i<=x;i=last+1){
last=x/(x/i); tmp=DJ_Sieve(x/i);
now.a-=tmp.a*(last-i+1); now.b-=tmp.b*(last-i+1);
}
H.Push(now); return now;
}
int main(){
Sieve();
int Case,n; Pii ans;
scanf("%d",&Case);
for(int i=1;i<=Case;i++){
scanf("%d",&n);
if(n==0) {printf("0 0\n"); continue;}
ans=DJ_Sieve(n);
printf("%lld %lld\n",ans.b,ans.a);
}
return 0;
}

  

●杜教筛入门(BZOJ 3944 Sum)的更多相关文章

  1. bzoj 3944 Sum —— 杜教筛

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3944 杜教筛入门题! 看博客:https://www.cnblogs.com/zjp-sha ...

  2. luogu 3768 简单的数学题 (莫比乌斯反演+杜教筛)

    题目大意:略 洛谷传送门 杜教筛入门题? 以下都是常规套路的变形,不再过多解释 $\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}ijgcd(i,j)$ $\sum ...

  3. bzoj 3944: Sum(杜教筛)

    3944: Sum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4930  Solved: 1313[Submit][Status][Discuss ...

  4. bzoj 3944: Sum【莫比乌斯函数+欧拉函数+杜教筛】

    一道杜教筛的板子题. 两个都是积性函数,所以做法是一样的.以mu为例,设\( f(n)=\sum_{d|n}\mu(d) g(n)=\sum_{i=1}^{n}f(i) s(n)=\sum_{i=1} ...

  5. 3944: Sum[杜教筛]

    3944: Sum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3471  Solved: 946[Submit][Status][Discuss] ...

  6. bzoj 3944 杜教筛

    题目中要求phi和miu的前缀和,利用杜教筛可以推出公式.我们令为 那么有公式 类比欧拉函数,我们可以推出莫比乌斯函数的和公式为  (公式证明懒得写了,主要核心是利用Dirichlet卷积的性质 ph ...

  7. BZOJ 4805: 欧拉函数求和 杜教筛

    https://www.lydsy.com/JudgeOnline/problem.php?id=4805 给出一个数字N,求sigma(phi(i)),1<=i<=N https://b ...

  8. BZOJ3944: Sum(杜教筛模板)

    BZOJ3944: Sum(杜教筛模板) 题面描述 传送门 题目分析 求\(\sum_{i=1}^{n}\mu(i)\)和\(\sum_{i=1}^{n}\varphi(i)\) 数据范围线性不可做. ...

  9. [BZOJ3944]Sum(杜教筛)

    3944: Sum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6201  Solved: 1606[Submit][Status][Discuss ...

随机推荐

  1. C语言博客作业—结构体

    一.PTA实验作业 题目1:结构体数组按总分排序 1. 本题PTA提交列表 2. 设计思路 void calc //函数calc求出p指针所指的结构体数组中 n 名学生各自的总分 { 定义循环变量i: ...

  2. python 面向对象之封装与类与对象

    封装 一,引子 从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,小老虎一起装进麻袋,然后把麻袋封上口子.照这种逻辑看,封装='隐藏',这种理解是相当片面的 二,先看如何隐藏 在 ...

  3. Linux系统把/home重新挂载到其他硬盘或分区

    一开始没有做好规划,导致/home空间不足,再加上分区表不是GPT,导致无法扩展超过2T,因此需要重新划分一块更大的硬盘给/home. 1.把新挂载的4T硬盘进行分区和格式化 2.创建目录 sudo ...

  4. wordpress怎么禁止文章复制

    登陆你的网站后台--点击菜单栏的"外观"--点击"编辑"--在右侧,找到footer.php,打开它--在</body>之前加入以下代码: 1.禁止 ...

  5. Tomcat(1-1)重置Tomcat8.5管理员的用户名和密码

    1.访问 http://localhost:8080/,点击 [manager app],提示输入用户名和密码,admin/admin后报错.  2.解决办法:重置Tomcat8.5管理员的用户名和密 ...

  6. 记一次将公司网站http换成https

    看了博客园将近一年了,一直都只是在被动的看,总觉得应该写点什么,但是又不知道该写点什么.今天正好公司要把网站由http换成https,那我就顺便记录一下吧. 由于之前没有弄过,所以就面向百度编程. 首 ...

  7. 模板引擎Jade详解

    有用的符号: | 竖杠后的字符会被原样输出 · 点表示下一级的所有字符都会被原样输出,不再被识别.(就是|的升级版,实现批量) include 表示引用外部文件 短杠说明后面跟着的字符只是一段代码(与 ...

  8. java Hibernate 处理 oracle xmltype类型

    网上关于如何处理oracle xmltype类型的博客很多,我现在分享的是针对具体业务来的,我在oracle数据库entity表中detail插入了一条xmltype类型的数据 xml的详细内容如下: ...

  9. Python面向对象进阶示例--自定义数据类型

    需求: 基于授权定制自己的列表类型,要求定制的自己的__init__方法, 定制自己的append:只能向列表加入字符串类型的值 定制显示列表中间那个值的属性(提示:property) 其余方法都使用 ...

  10. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...