P4213 【模板】杜教筛(Sum)

题目描述

给定一个正整数$N(N\le2^{31}-1)$

$$ans_1=\sum_{i=1}^n\varphi(i)$$

$$ans_2=\sum_{i=1}^n \mu(i)$$

输入输出格式

输入格式:

一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问

输出格式:

一共T行,每行两个用空格分隔的数ans1,ans2

输入输出样例

输入样例#1:
复制

6
1
2
8
13
30
2333
输出样例#1:
复制

1 1
2 0
22 -2
58 -3
278 -3
1655470 2

AcFirmament的题解

杜教筛模板

杜教筛是用来干蛤的呢?

它可以在非线性时间内求积性函数前缀和。

前置知识

积性函数

积性函数:对于任意互质的整数 $a,b$ 有 $f(ab)=f(a)f(b)$ 则称 $f(x)$ 的数论函数。

完全积性函数:对于任意整数 $a,b$ 有 $f(ab)=f(a)f(b)$ 的数论函数。

  • 常见的积性函数:$\varphi,\mu,\sigma,d$
  • 常见的完全积性函数:$\epsilon,I,id$

这里特殊解释一下 $\epsilon,I,id$ 分别是什么意思:
$\epsilon(n) = [n=1], I(n) = 1, id(n) = n$

狄利克雷卷积

设 $f, g$ 是两个数论函数,它们的狄利克雷卷积卷积是:$(f*g)(n) = \sum \limits _{d | n} f(d) g(\frac{n}{d})$

性质:满足交换律,结合律

单位元:$\epsilon$ (即 $f*\epsilon=f$)

结合狄利克雷卷积得到的几个性质:

  1. $\mu * I = \epsilon$
  2. $\varphi * I = id$
  3. $\mu * id = \varphi$

莫比乌斯反演


$$g(n) = \sum\limits_{d|n}f(d)$$


$$f(n)=\sum\limits_{d|n}\mu(d)g(\frac{n}{d})$$

证明:这里需要用到前面提到的性质:$\mu * I = \epsilon$

给出的条件等价于 $g=f * I$

所以 $g*\mu=f*I*\mu=f*\epsilon=f$ 即 $g * \mu = f$ 即 结论。


杜教筛

设现在要求积性函数 $f$ 的前缀和, 设 $\sum \limits_{i=1}^{n} f(i) = S(n)$。

再找一个积性函数 $g$ ,则考虑它们的狄利克雷卷积的前缀和

$$\sum\limits_{i=1}^{n}(f*g)(i)$$

$$\begin{aligned} &= \sum\limits_{i=1}^{n} \sum \limits _{d|i} f(d)g(\frac{i}{d}) \\ &= \sum \limits _{d=1}^{n} g(d)\sum\limits _{i=1}^{\lfloor \frac{n}{d}\rfloor } f(i) \\ &= \sum \limits _{d=1}^{n} g(d) S(\lfloor \frac{n}{d} \rfloor) \end{aligned}$$

其中得到第一行是根据狄利克雷卷积的定义。

得到第二行则是先枚举 $d$ 提出 $g$ 。

得到第三行则是把 $\sum\limits _{i=1}^{\lfloor \frac{n}{d}\rfloor } f(i) $ 替换为 $S(\lfloor \frac{n}{d} \rfloor) $

接着考虑 $g(1)S(n)$ 等于什么。

可以发现,他就等于
$$ \sum \limits _{i=1}^{n} g(i) S(\lfloor \frac{n}{i} \rfloor) - \sum \limits _{i=2}^{n} g(i) S(\lfloor \frac{n}{i} \rfloor)$$

(可以理解成从1开始的前缀和减去从2开始的前缀和就是第一项)

前面这个式子$\sum \limits _{i=1}^{n} g(i) S(\lfloor \frac{n}{i} \rfloor)$ ,根据刚才的推导,他就等于 $\sum\limits_{i=1}^{n}(f*g)(i)$

所以得到杜教筛的核心式子:

$$g(1)S(n)=\sum\limits_{i=1}^{n}(f*g)(i) - \sum \limits _{i=2}^{n} g(i) S(\lfloor \frac{n}{i} \rfloor)$$

得到这个式子之后有什么用呢?

现在如果可以找到一个合适的积性函数 $g$ ,使得可以快速算出 $\sum\limits_{i=1}^{n}(f*g)(i)$ 和 $g$ 的前缀和,便可以用数论分块递归地求解。

代码按照理解大概可以写成这样(默认 lllong long
(可以理解成一个伪代码。。就是一个思路的框架)

ll GetSum(int n) { // 算 f 前缀和的函数
ll ans = f_g_sum(n); // 算 f * g 的前缀和
// 以下这个 for 循环是数论分块
for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
r = (n / (n / l));
ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);
// g_sum 是 g 的前缀和
// 递归 GetSum 求解
} return ans;
}

这个代码的复杂度是 $O(n^{\frac{3}{4}})$,证明如下:

设求出 $S(n)$ 的复杂度是 $T(n)$ ,要求出 $S(n)$ 需要求出 $\sqrt n$ 个 $S (\lfloor \frac{n}{i} \rfloor)$ 的值,结合数论分块的复杂度 $O(\sqrt n)$ 可得:
$$T(n) = \sum\limits_{i=1}^{\sqrt n} O(\sqrt i) + O(\sqrt {\frac{n}{i}})=O(n^{\frac{3}{4}})$$

还可以进一步优化杜教筛,即先线性筛出前 $m$ 个答案,之后再用杜教筛。这个优化之后的复杂度是:

$$T(n) = \sum\limits_{i=1}^{\lfloor \frac{n}{m} \rfloor} \sqrt \frac{n}{i} = O({\frac{n}{\sqrt m}})$$

当 $m = n ^ {\frac{2}{3}}$ 时,$T(n) = O(n^{\frac{2}{3}})$

可以使用哈希表来存下已经求过的答案,也可以不用。

考虑到上面的求和过程中出现的都是 $\lfloor \frac{n}{i} \rfloor $ 。开一个大小为两倍 $\sqrt n$ 的数组 $dp$ 记录答案。如果现在需要求出 GetSum(x) ,若 $x \leq \sqrt n$ ,返回 dp[x] ,否则返回 dp[sqrt n + n / i] 即可。这样可以省去哈希表的复杂度。



实战演练

再挂一次核(tao)心(lu)式,全都要靠它:
$$g(1)S(n)=\sum\limits_{i=1}^{n}(f*g)(i) - \sum \limits _{i=2}^{n} g(i) S(\lfloor \frac{n}{i} \rfloor)$$

它的关键就是要找到合适的 $g$ 使得这个东西可以快速地算。

理论知识大概就这么多,接下来看几个例子:

(1) $\mu$ 的前缀和

考虑到莫比乌斯函数的性质 $\mu * I = \epsilon$ ,自然想到取 $f=\mu,g=I,f*g=\epsilon$ 。

其中 $I$ 的前缀和和 $\epsilon$ 的前缀和都弱到爆了。。

所以就轻松的解决了。

杜教筛代码:

inline ll GetSumu(int n) {
if(n <= N) return sumu[n]; // sumu是提前筛好的前缀和
if(Smu[n]) return Smu[n]; // 记忆化
ll ret = 1ll; // 单位元的前缀和就是 1
for(int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSumu(n / l);
// (r - l + 1) 就是 I 在 [l, r] 的和
} return Smu[n] = ret; // 记忆化
}

(2) $\varphi$ 的前缀和

考虑到 $\varphi$ 的性质 $\varphi * I = id$,取 $f = \varphi, g = I, f * g = id$

$f * g$ 即 $id$ 的前缀和为 $\frac{n * (n+1)}{2}$

杜教筛代码:

inline ll GetSphi(int n) {
if(n <= N) return sump[n]; // 提前筛好的
if(Sphi[n]) return Sphi[n]; // 记忆化
ll ret = 1ll * n * (n + 1) / 2; // f * g = id 的前缀和
for(int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSphi(n / l);
// 同上,因为两个的 g 都是 I
} return Sphi[n] = ret; // 记忆化
}

(1) & (2) 就是杜教筛模板 luogu p4213

(3) (综合)$\sum\limits_{i=1}^{n}\varphi(i) \cdot i$

令 $f = \varphi \cdot id, g = id$, 考虑迪利克雷卷积的形式得到 $(f*g)(n)=\sum \limits _{d|n} (\varphi(d) \cdot d) \cdot (\frac{n}{d}) = n \sum\limits_{d|n}\varphi(d)=n^2$

即 $(f * g)(i) = i^2$

这样就可以快速求得 $(f*g)(i)$ 的前缀和 $\frac{n(n+1)(2n+1)}{6}$

就可以了。



题目

先推荐洛谷模板题

还有一题 luoguP3768 简单的数学题,这道题推完式子可以用杜教筛来求 $\varphi(i)i^2$ 的前缀和,和 $\varphi(i)i$ 所差无几。

51nod 上也有很多杜教筛的题目,放几个:

  • 51nod 1244
  • 51nod 1237
  • 51nod 1238
  • 51nod 1239
  • 51nod 1220
  • ...

然后就是卡常优化,卡着开空间,unordered_map乱搞。

#include<bits/stdc++.h>
#define il inline
#define co const
template<class T>T read(){
T data=0,w=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(T&x) {return x=read<T>();}
typedef long long LL;
using namespace std; co int N=6500000;
int pri[N],tot;
LL mu[N],phi[N];
void sieve(){
pri[1]=mu[1]=phi[1]=1;
for(int i=2;i<N;++i){
if(!pri[i]) pri[++tot]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=tot&&i*pri[j]<N;++j){
pri[i*pri[j]]=1,mu[i*pri[j]]=-mu[i],phi[i*pri[j]]=phi[i]*phi[pri[j]];
if(i%pri[j]==0){
mu[i*pri[j]]=0,phi[i*pri[j]]=phi[i]*pri[j];
break;
}
}
}
for(int i=2;i<N;++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
unordered_map<int,LL> smu,sphi;
LL sum_mu(int n){
if(n<N) return mu[n];
if(smu.count(n)) return smu[n];
LL ans=1;
for(unsigned l=2,r;l<=n;l=r+1){ // 2^32-1
r=n/(n/l);
ans-=(r-l+1)*sum_mu(n/l);
}
return smu[n]=ans;
}
LL sum_phi(int n){
if(n<N) return phi[n];
if(sphi.count(n)) return sphi[n];
LL ans=(LL)n*(n+1)/2;
for(unsigned l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=(r-l+1)*sum_phi(n/l);
}
return sphi[n]=ans;
}
int main(){
cerr<<(sizeof(pri)+sizeof(phi)+sizeof(mu))/1024.0/1024<<endl;
sieve();
for(int t=read<int>();t--;){
int n=read<int>();
printf("%lld %lld\n",sum_phi(n),sum_mu(n));
}
return 0;
}

jklover:整除是可以结合的,所以才有开数组那一说。

4916: 神犇和蒟蒻

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1085  Solved: 589
[Submit][Status][Discuss]

Description

很久很久以前,有一只神犇叫yzy;
很久很久之后,有一只蒟蒻叫lty;

Input

请你读入一个整数N;1<=N<=1E9,A、B模1E9+7;

Output

请你输出一个整数A=\sum_{i=1}^N{\mu (i^2)};
请你输出一个整数B=\sum_{i=1}^N{\varphi (i^2)};

Sample Input

1

Sample Output

1

1

HINT

Source

[Submit][Status][Discuss]

HOME
Back

题解

第一问答案就是1。

对于第二问,\(\varphi(n^2)\)用定义式写开,发现就是\(n\varphi(n)\)。然后就是上面那份题解里面的(3)综合

\(\varphi\cdot id * id=id^2\)

LG4213 【模板】杜教筛(Sum)和 BZOJ4916 神犇和蒟蒻的更多相关文章

  1. BZOJ4916: 神犇和蒟蒻(杜教筛)

    题意 求 $$\sum_{i = 1}^n \mu(i^2)$$ $$\sum_{i = 1}^n \phi(i^2)$$ $n \leqslant 10^9$ Sol zz的我看第一问看了10min ...

  2. BZOJ4916: 神犇和蒟蒻【杜教筛】

    Description 很久很久以前,有一只神犇叫yzy; 很久很久之后,有一只蒟蒻叫lty; Input 请你读入一个整数N;1<=N<=1E9,A.B模1E9+7; Output 请你 ...

  3. BZOJ4916 神犇和蒟蒻(欧拉函数+杜教筛)

    第一问是来搞笑的.由欧拉函数的计算公式容易发现φ(i2)=iφ(i).那么可以发现φ(n2)*id(n)(此处为卷积)=Σd*φ(d)*(n/d)=nΣφ(d)=n2 .这样就有了杜教筛所要求的容易算 ...

  4. [BZOJ4916]神犇和蒟蒻 杜教筛/Min_25筛

    题目大意: 给定\(n\le 10^9\),求: 1.\(\sum_{i=1}^n\mu(i^2)\) 2.\(\sum_{i=1}^n\varphi(i^2)\) 解释 1.\(\sum_{i=1} ...

  5. BZOJ4916 神犇和蒟蒻 【欧拉函数 + 杜教筛】

    题目 很久很久以前,有一只神犇叫yzy; 很久很久之后,有一只蒟蒻叫lty; 输入格式 请你读入一个整数N;1<=N<=1E9,A.B模1E9+7; 输出格式 请你输出一个整数A=\sum ...

  6. Bzoj4916: 神犇和蒟蒻

    题面 传送门 Sol 第一问puts("1") 第二问,\(\varphi(i^2)=i\varphi(i)\) 设\(\phi(n)=\sum_{i=1}^{n}i\varphi ...

  7. 【BZOJ4916】神犇和蒟蒻(杜教筛)

    [BZOJ4916]神犇和蒟蒻(杜教筛) 题面 BZOJ 求 \[\sum_{i=1}^n\mu(i^2)\ \ 和\ \sum_{i=1}^n\phi(i^2)\] 其中\[n<=10^9\] ...

  8. 【BZOJ4916】神犇和蒟蒻 解题报告

    [BZOJ4916]神犇和蒟蒻 Description 很久很久以前,有一群神犇叫sk和ypl和ssr和hjh和hgr和gjs和yay和xj和zwl和dcx和lyy和dtz和hy和xfz和myh和yw ...

  9. p4213 【模板】杜教筛(Sum)

    传送门 分析 我们知道 $\varphi * 1 = id$ $\mu * 1 = e$ 杜教筛即可 代码 #include<iostream> #include<cstdio> ...

随机推荐

  1. Zookeeper架构及FastLeaderElection机制

    原文链接:http://www.jasongj.com/zookeeper/fastleaderelection/ Zookeeper是什么 Zookeeper是一个分布式协调服务,可用于服务发现,分 ...

  2. Windows下mysql安装配置问题

    下载最新版的mysql: https://dev.mysql.com/downloads/mysql/ 下载完成后解压打开安装包如下 打开cmd以管理员身份运行(一定要以管理员身份运行) 然后输入命令 ...

  3. [转帖]Helm V2 迁移到 V3 版本

    Helm V2 迁移到 V3 版本 -- :: Mr-Liuqx 阅读数 63更多 分类专栏: kubernetes 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上 ...

  4. Python之让 字符串内的转义字符 不做任何处理

    一.在字符串前面加上 'r' 就可以了 print("\ntext_1") print(r"\ntest_2") 二.在转义字符的 '\' 前面再加一个 '\' ...

  5. 【Qt开发】菜单栏,工具栏和状态栏

    概述 菜单栏,工具栏,状态栏应用中经常见到,下图解释一目了然,实际开发中 两种方式来实现,一种是使用纯代码QMenuBar,QToolBar,QStatusBar来设计开发,另一种使用Qt Desig ...

  6. Go语言( 运算符)

    运算符用于在程序运行时执行数学或逻辑运算. 运算符 Go 语言内置的运算符有: 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 算数运算符 运算符 描述 + 相加 - 相减 * 相乘 / 相 ...

  7. ByteArray、16进制、字符串之间的转换

    ByteArray.16进制.字符串之间的转换: package fengzi.convert { import flash.utils.ByteArray; public class ByteArr ...

  8. redis的事务处理

    1.redis事务可以依次执行多个命令,并且带有以下三个重要的保证: 批量操作在发送exec命令前被放入队列缓存. 收到exec命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行. 在事 ...

  9. mpvue + vant + flyio 小程序项目总结

    vant 的使用 我开始是 npm 导入,然后 import,使用不了. 找了各种方法,最后还是下载文件,然后找到 dist 文件夹,复制到项目里,我是放在 static 文件夹,文件名 dist 重 ...

  10. Docker安装带中文全文搜索插件zhparser的Postgresql数据库

    上一篇讲了在已经安装了PG数据库的情况下,安装全文搜索插件zhparser遇到的问题.在一个全新的环境中安装带有全文搜索插件zhparser的PG数据库,可以使用已经做好的Docker镜像,在安装的过 ...