杜教筛

浅谈一类积性函数的前缀和 - skywalkert's space - CSDN博客

杜教筛可以在\(O(n^{\frac 23})\)的时间复杂度内利用卷积求出一些积性函数的前缀和.

算法

给定\(f(n)\), 现要求\(S(n)=\sum_{i=1}^n f(i)\).

定义卷积运算 \((f*g)(n) = \sum_{d | n} f(d) g(\frac{n}{d})\).

如果存在\(g(n)\), 满足\(f*g=h\), 且\(g\)和\(h\)都能 \(O(1)\) 求出前缀和, 我们可以较快地求出\(S(n)\).

注意到

\[\begin{aligned}
\sum\limits_{i=1}^{n}(f*g)(i) &= \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}
\]

因此, 有

\[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)
\]

可以递归(并记忆化)下去.

对于复杂度: 展开一层递归, 通过积分可以求出时间复杂度为 \(O(n^{\frac 34})\).

如果预处理前 \(m\) 个答案, 利用同样的方法可以得到复杂度为 \(O(m + \frac n{\sqrt m})\), 当 \(m = n^{\frac 23}\) 时取最小值为 \(O(n^{\frac 23})\).

并不知道为什么算复杂度时可以只展开一层

Upd: 关于为什么算复杂度时只展开一层:

递归的 \(x\) 显然为 \(\lfloor \frac ni \rfloor\) 的形式, 可以通过哈希表(或者下面的另一种方法)存储. 那么递归到第二层的时候会发现要求的值已经求过了, 因此只需展开一层就行了.

关于卷积

显然, 卷积运算满足交换律和结合律, 可以推式子验证一下.

另外, 积性函数的卷积仍然为积性函数.

定义函数 \(\epsilon(n) = [n=1], I(n) = 1, id(n) = n\), 有

\[f * \epsilon = f
\]

这是\(\epsilon\)函数的定义.

\[\phi * I = id
\]

\[\mu * I = \epsilon
\]

这是莫比乌斯函数的定义.

\[\mu * id = \phi
\]

\[id * id = id \cdot d
\]

\[(\phi \cdot id) * id = id^2
\]

Problem Description

求 \(\phi (n)\) 和 \(\mu (n)\) 的前缀和. \(1 \le n \le 2^{31}-1\).

Code

另外, 卡常数...

用long long会TLE, 改成unsigned int就不会.

似乎不少毒瘤数论题都卡常

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<unordered_map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint; //---------------------------------------
const int blsz=5e6+50,sqsz=5e4+50;
ll bnd=5e6;
ll t,n; int nopr[blsz],pr[blsz],pp=0;
ll mu[blsz],phi[blsz];
void init(){
nopr[1]=mu[1]=phi[1]=1;//a
rep(i,2,bnd){
if(nopr[i]==0)pr[++pp]=i,mu[i]=-1,phi[i]=i-1;//b
rep(j,1,pp){
if(i*pr[j]>bnd)break;
nopr[i*pr[j]]=1;
if(i%pr[j])mu[i*pr[j]]=-mu[i],phi[i*pr[j]]=phi[i]*phi[pr[j]];
else{mu[i*pr[j]]=0,phi[i*pr[j]]=phi[i]*pr[j];break;}
}
}
rep(i,1,bnd)phi[i]+=phi[i-1],mu[i]+=mu[i-1];
} //ll sq,vmu[n12sz*2],vphi[n12sz*2];
//ll tr(ll v){return v<} unordered_map<uint,ll> ansmu,ansphi; ll getphi(uint n){
if(n<=bnd)return phi[n];
ll &tmp=ansphi[n];
if(tmp)return tmp;
ull res=(ull)n*(n+1)/2;
for(uint l=2,r;l<=n;l=r+1){//using unsigned int instead of ll
r=n/(n/l);
res-=(ll)(r-l+1)*getphi(n/l);
}
return tmp=res;
} ll getmu(uint n){
if(n<=bnd)return mu[n];
ll &tmp=ansmu[n];
if(tmp)return tmp;
tmp=1;
for(uint l=2,r;l<=n;l=r+1){
r=n/(n/l);
tmp-=(r-l+1)*getmu(n/l);
}
return tmp;
} int main(){
// freopen("a.in","r",stdin);
ios::sync_with_stdio(0),cin.tie(0);
init();
cin>>t;
rep(cs,1,t){
cin>>n;
cout<<getphi(n)<<' '<<getmu(n)<<'\n';
}
return 0;
}

unordered_map的地方也可以换为

struct tmap{
ll a[sqsz],b[sqsz];
void cl(){memset(b,0,sizeof(b));}
ll& operator[](int p){
if(p<5e4)return a[p];
else return b[n/p];
}
}ansmu,ansphi;

但是并没有变快... 可能是unordered_map常数小吧...

[模板] 杜教筛 && bzoj3944-Sum的更多相关文章

  1. 杜教筛 && bzoj3944 Sum

    Description Input 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 Output 一共T行,每行两个用空格分隔的数ans1,ans ...

  2. LG4213 【模板】杜教筛(Sum)和 BZOJ4916 神犇和蒟蒻

    P4213 [模板]杜教筛(Sum) 题目描述 给定一个正整数$N(N\le2^{31}-1)$ 求 $$ans_1=\sum_{i=1}^n\varphi(i)$$ $$ans_2=\sum_{i= ...

  3. Luogu 4213 【模板】杜教筛(Sum)

    当作杜教筛的笔记吧. 杜教筛 要求一个积性函数$f(i)$的前缀和,现在这个东西并不是很好算,那么我们考虑让它卷上另外一个积性函数$g(i)$,使$(f * g)$的前缀和变得方便计算,然后再反推出这 ...

  4. luoguP4213 【模板】杜教筛(Sum)杜教筛

    链接 luogu 思路 为了做hdu来学杜教筛. 杜教筛模板题. 卡常数,我加了register居然跑到不到800ms. 太深了. 代码 // luogu-judger-enable-o2 #incl ...

  5. [洛谷P4213]【模板】杜教筛(Sum)

    题目大意:给你$n$,求:$$\sum\limits_{i=1}^n\varphi(i),\sum\limits_{i=1}^n\mu(i)$$最多$10$组数据,$n\leqslant2^{31}- ...

  6. P4213 【模板】杜教筛(Sum)

    \(\color{#0066ff}{题 目 描 述}\) 给定一个正整数\(N(N\le2^{31}-1)\) 求 \(\begin{aligned} ans_1=\sum_{i=1}^n\varph ...

  7. 【模板】杜教筛(Sum)

    传送门 Description 给定一个正整数\(N(N\le2^{31}-1)\) 求 \[ans1=\sum_{i=1}^n \varphi(i)\] \[ans_2=\sum_{i=1}^n \ ...

  8. P4213【模板】杜教筛(Sum)

    思路:杜教筛 提交:\(2\)次 错因:\(\varphi(i)\)的前缀和用\(int\)存的 题解: 对于一类筛积性函数前缀和的问题,杜教筛可以以低于线性的时间复杂度来解决问题. 先要构造\(h= ...

  9. luoguP4213 [模板]杜教筛

    https://www.luogu.org/problemnew/show/P4213 同 bzoj3944 考虑用杜教筛求出莫比乌斯函数前缀和,第二问随便过,第一问用莫比乌斯反演来做,中间的整除分块 ...

随机推荐

  1. 视频拉流 Linux安装FFmpeg

    1 下载最新源码包并解压 $ wget http://ffmpeg.org/releases/ffmpeg-3.1.3.tar.bz2 $ tar jxvf ffmpeg-.tar.bz2 2安装ya ...

  2. arcgis api 3.x for js 入门开发系列七图层控制(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  3. 如何用ABP框架快速完成项目(面向项目交付编程面向客户编程篇)(1) - 目录

    昨天发表了<如何用ABP框架快速完成项目 - 自动化测试 - 前端angular e2e protractor>后,大家十分热情,几个小时内就收到了不少问题,包括: 对于ui自动化测试这方 ...

  4. 当view为wrap_conten时获取一个view的具体宽高

    int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); int h = View.MeasureSpec. ...

  5. linux下执行QT可执行文件报错

    老样子,不多BiBi,直接进入主题! 有时候在linux下编译好QT程序,用QTCreator运行没问题,打包移植到另一台机器上,用命令./XX执行就会报错:error while loading s ...

  6. java新知识系列 三

    1:trycatch中需要注意的地方. 2:ServletConfig以及ServletContext对象. 3: Spring事务属性的种类:   传播行为.隔离级别.只读和事务超时. 5:关于程序 ...

  7. redis 慢日志查询

    Intro 可能有一些命令需要很长时间才能在redis服务器上处理,导致请求超时. 长时间运行的命令的很少例子有 mget有大量的键,键*或写得不好的lua脚本. 可以运行通过 SlowLog 命令查 ...

  8. [Python][小知识][NO.5] 使用 Pyinstaller 打包成.exe文件

    1.安装 pyinstaller 插件 cmd命令:pip install PyInstaller PS . o.o 不知道 easy_install 的百度吧. 2.pyinstaller 简介 他 ...

  9. C#的自动拼接Sql语句Insert方法及思路

    思路: 1.想想插入语句,大概是这样的一个框架:INSERT INTO 表名 (数据库列名) values (值) 2.这里要3个变量是不固定的,分别是:表名.数据库列名.值: a.表名我们这里很容易 ...

  10. 在windows下搭建汇编编程环境

    汇编语言程序搭建masm+debug 下载链接 dosbox:链接:https://pan.baidu.com/s/1TgkfU-d5w6Nz9TOYro1pYw 密码:mp83 masm:链接:ht ...