本题是一道讲解根号分治思想的论文题(然鹅我并无找到论文),正ios
如论文中所说,根号算法——不只是分块,根号分治利用的思想和分块像c++
似却又不一样,某一篇洛谷日报中说过,分块算法实质上是一种是经过分红算法
多块后在每块上打标记以实现快速区间修改,区间查询的一种算法。根号优化
分治与其思路类似,将本来若一次性解决时间复杂度很高的问题分块去解spa
决来下降总体的时间复杂度。code
以本题举例子哈希冲突ci
本题做为论文的第一道题目,是一道很好的练习题,注意,本体给出的get
\(value[i]\) 是 \(i\) 在序列中出现的次数,不要把题读错了(一开始我就读错了)string
咱们首先阅读题目,发现,不管是 \(O(n^2)\) 预处理, \(O(1)\) 查询,仍是在io
查询时直接\(O(n^2)\)获取答案,都是 \(O(n^2)\) 的时间复杂度,咱们考虑对
其进行优化,咱们能够考虑将\(p\),也就是模数按根号分块处理
对于 \(p<=\sqrt{q}\) 咱们直接 \(O(n\sqrt{n})\) 进行预处理,
for(int i=1;i<=n;i++){ v=read(); val[i]=v; } size=sqrt(n); for(int i=1;i<=n;i++){ for(int p=1;p<=size;p++){ ans[p][i%p]+=val[i]; } }
\(ans[p][i]\) 表示在 \(%p\) 后值为 \(i\)的数的个数
对 \(p>\sqrt{q}\) 的状况,
咱们直接暴力得出答案,暴力获得答案的时间复杂度为 \(O(\sqrt{n})\)
int an=val[y]; for(int i=x+y;i<=n;i+=x){ an+=val[i]; } cout<<an<<endl;
\(an=val[y]\) 是为了处理 \(y%x=y\) \((y<x)\) 的状况,为何说咱们暴力跳
答案时间复杂度是 \(O(\sqrt{n})\) 呢?咱们当前的 \(p>\sqrt{n})\) 由于统
计答案时每一次要跳\(p\)个数,因此有贡献的数必定小于 \(\frac{n} {p}\) 也就是 \(\sqrt{n}\) ,因此暴力获得答案的时间复杂度为 \(O(\sqrt{n})\)
每一次修改,咱们只须要修改 \(p<=\sqrt{n}\) 的状况便可,时间复杂度也是 \(O(\sqrt{n})\)
cin>>x>>y; int l=y-val[x]; val[x]=y; for(int p=1;p<=size;p++){ ans[p][x%p]+=l; }
因此在本题,咱们运用根号分治的想法,把时间复杂度由本来的\(O(n^2)\)
优化到了 \(O(n\sqrt{n})\) 从而解决本题。
莫名以为根号分治挺像折半搜索
,推荐一道练习题CF444D DZY Loves Strings
仍是颇有难度的
放一下所有代码吧
#include<iostream> #include<string> #include<string> #include<cstdio> #include<cmath> #define int long long using namespace std; const int maxn=3e5+10; inline int read(){ int ret=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-f; ch=getchar(); } while(ch<='9'&&ch>='0'){ ret=ret*10+(ch^'0'); ch=getchar(); } return ret*f; } int val[maxn]; int n,m; int p; int ans[2000][2000]; int size; char a; signed main(){ // freopen("a.in","r",stdin); n=read(); m=read(); int v; for(int i=1;i<=n;i++){ v=read(); val[i]=v;//???????? } size=sqrt(n);//???? for(int i=1;i<=n;i++){ for(int p=1;p<=size;p++){ ans[p][i%p]+=val[i]; } } int x,y; while(m--){ cin>>a; if(a=='A'){ x=read(); y=read(); if(x<=size){ cout<<ans[x][y]<<endl; } else{ int an=val[y]; for(int i=x+y;i<=n;i+=x){ an+=val[i]; } cout<<an<<endl; } } if(a=='C'){ cin>>x>>y; int l=y-val[x]; val[x]=y; for(int p=1;p<=size;p++){ ans[p][x%p]+=l; } } } return 0; }
到这里本题解就结束了
完结撒花!!