博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[模板] 杜教筛 && bzoj3944-Sum
阅读量:6981 次
发布时间:2019-06-27

本文共 3176 字,大约阅读时间需要 10 分钟。

杜教筛

杜教筛可以在\(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
#include
#include
#include
#include
#include
#include
#include
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 inlinetypedef 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
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<
<<' '<
<<'\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常数小吧...

转载于:https://www.cnblogs.com/ubospica/p/10282358.html

你可能感兴趣的文章
Juniper-R&S-BGP(1):一些写在前头的基础知识
查看>>
python flaskfeng封装跨域请求头和封装json格式
查看>>
整理 iOS 9 适配中出现的坑(图文)
查看>>
17款jQuery在线QQ客服代码分享
查看>>
Linux下好用的api工具(同mac下的Dash)
查看>>
【产品日记】51CTO用户中心v1.1发布
查看>>
primesfaces入门 ,配置
查看>>
怎么用js来获取 fileupload中的上传文件的文件名。
查看>>
创建tableview
查看>>
22个所见即所得在线 Web 编辑器
查看>>
CentOS memcached安装和启动
查看>>
birt报表按字段分组后批量打印(每个字段数据一页)以及空数据显示特定字段...
查看>>
ubuntu安装oracle10G的时候界面乱码.
查看>>
尝试OUTFIle、INFILE快速导入导出数据
查看>>
“形式”系统的含义辨析
查看>>
【搜索引擎基础知识2】网络爬虫
查看>>
Aptana Studio 3 汉化
查看>>
phonegap+jquerymobile开发android的心得(4)
查看>>
python 使用PyTesser--安装
查看>>
MAC 上使用pem秘钥 远程登录linux
查看>>