HDU5381【莫队算法+区间GCD特性】
前言:
主要最近在刷莫队的题,这题GCD的特性让我对莫队的使用也有了新的想法。给福利:神犇的一套莫队算法题
先撇开题目,光说裸的一个莫队算法,主要的复杂度就是n*sqrt(n)对吧,这里我忽略了一个左端点(增加/删除)或者右端点(增加/删除)的所带来的复杂度,
之前也遇到过卡这里的复杂度,但是是因为简单的long long计算多而造成了复杂度增大,从而转变一下。
回到这道题:给出区间,求所有子区间的gcd和。
思路:
莫队算法+gcd的特性。
外面就是套了一个莫队,排序然后离散化操作优化了复杂度得n*sqrt(n)。
然后呢?我们要去计算一个右结点的增加或删除的贡献。
先预处理所有区间之间的gcd,利用ST表。
在这里:当一个右端点的删除/增加
问题就是:如何快速求所有存在这个右端的子区间的GCD的贡献。
这里利用的是区间gcd的特性,一段区间上不同的gcd最多只有logn个。
对于右端点:
预处理右端点固定,不同gcd的区间段的GCD(直接枚举,更新位置,由于一段区间GCD的gcd个数不会超过logn,所以最多会预处理logn段不同的gcd段),并且预处理右端固定的不同gcd段的最远位置(用二分就行,因为GCD会随着区间大而变小,当前区间最小即最大),所以每次查询时间要乘以logn;
对于左端点同理;
总的复杂度:O(n*sqrt(n)*log(n))。
代码还有一些简要注释可以参考。
这个代码打不出来...就多打打!练手!23333333333
- #include <bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- typedef pair<int,int> PII;
- const int N=1e4+10;
- int a[N],n,m;
- vector<PII>VL[N];
- vector<PII>VR[N];
- int pos[N];
- struct asd{
- int left,right,id;
- LL res;
- };
- asd S[N];
- bool cmp(asd x,asd y)
- {
- if(pos[x.left]==pos[y.left]) return x.right<y.right;
- return pos[x.left]<pos[y.left];
- }
- //RMQ预处理,以某个端点为起点向一个方向延伸的区间的gcd的最远延伸的方向和对应的gcd
- //Rmq[i][j]表示第 i 个数起,连续 2^j 个数的GCD;
- int Rmq[N][15];
- void GetRmq()
- {
- for(int i=1; i<=n; i++)
- Rmq[i][0]=a[i];
- for(int i=1; (1<<i)<=n; i++)
- for(int j=1; j<=n; j++)
- if(j+(1<<i)-1<=n)
- Rmq[j][i]=__gcd(Rmq[j][i-1],Rmq[j+(1<<(i-1))][i-1]);
- }
- int query(int L, int R)
- {
- int k=(int)log2(R-L+1);
- return __gcd(Rmq[L][k],Rmq[R-(1<<k)+1][k]);
- }
- //固定s为右端点,向左延伸gcd为t的最远位置
- int Rsearch(int s,int L,int R,int t)
- {
- int ans;
- while(L<=R)
- {
- int mid=(L+R)>>1;
- if(query(mid,s)==t)
- {
- ans=mid;
- R=mid-1;
- }
- else L=mid+1;
- }
- return ans;
- }
- //固定s为左端点,向右延伸gcd为t的最远位置
- int Lsearch(int s,int L,int R,int t)
- {
- int ans;
- while(L<=R)
- {
- int mid=(L+R)>>1;
- if(query(s,mid)==t)
- {
- ans=mid;
- L=mid+1;
- }
- else R=mid-1;
- }
- return ans;
- }
- //计算s为右端点的贡献,t 为当前区间左端点
- LL Rcal(int s,int t)
- {
- LL ans=0;
- int ss=s;
- for(int i=0;i<VR[s].size();i++)
- {
- ans+=(1LL*(ss-max(t,VR[s][i].second)+1)*VR[s][i].first);
- ss=VR[s][i].second-1;
- if(ss<t) break;
- }
- return ans;
- }
- //计算s为左端点的贡献,t 为当前区间右端点
- LL Lcal(int s,int t)
- {
- LL ans=0;
- int ss=s;
- for(int i=0;i<VL[s].size();i++)
- {
- ans+=(1LL*(min(t,VL[s][i].second)-ss+1)*VL[s][i].first);
- ss=VL[s][i].second+1;
- if(ss>t) break;
- }
- return ans;
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while(T--)
- {
- scanf("%d",&n);
- int block=(int)sqrt(n);
- for(int i=1; i<=n; i++)
- {
- scanf("%d",&a[i]);
- pos[i]=(i-1)/block+1;
- }
- GetRmq();
- //预处理左端 i 固定的不同gcd区间段
- for(int i=1;i<=n;i++)
- {
- int r=i;
- VL[i].clear();
- while(r<=n)
- {
- int ant=query(i,r);
- r=Lsearch(i,r,n,ant);
- VL[i].push_back(make_pair(ant,r));
- r++;
- }
- }
- //预处理右端 i 固定的不同gcd区间段
- for(int i=n;i>=1;i--)
- {
- int l=i;
- VR[i].clear();
- while(l>=1)
- {
- int ant=query(l,i);
- l=Rsearch(i,1,l,ant);
- VR[i].push_back(make_pair(ant,l));
- l--;
- }
- }
- scanf("%d",&m);
- for(int i=0;i<m;i++)
- {
- scanf("%d%d",&S[i].left,&S[i].right);
- S[i].id=i;
- }
- sort(S,S+m,cmp);
- LL sum=0;
- int l=0,r=1;
- for(int i=0;i<m;i++)
- {
- while(r<=S[i].right)
- {
- sum+=Rcal(r,l+1);
- r++;
- }
- while(r>S[i].right+1)
- {
- r--;
- sum-=Rcal(r,l+1);
- }
- while(l<S[i].left-1)
- {
- l++;
- sum-=Lcal(l,r-1);
- }
- while(l>=S[i].left)
- {
- sum+=Lcal(l,r-1);
- l--;
- }
- S[S[i].id].res=sum;
- }
- for(int i=0;i<m;i++)
- printf("%lld\n",S[i].res);
- }
- return 0;
- }
HDU5381【莫队算法+区间GCD特性】的更多相关文章
- hdu5381 The sum of gcd]莫队算法
题意:http://acm.hdu.edu.cn/showproblem.php?pid=5381 思路:这个题属于没有修改的区间查询问题,可以用莫队算法来做.首先预处理出每个点以它为起点向左和向右连 ...
- HDU 5381 The sum of gcd (技巧,莫队算法)
题意:有一个含n个元素的序列,接下来有q个询问区间,对每个询问区间输出其 f(L,R) 值. 思路: 天真单纯地以为是道超级水题,不管多少个询问,计算量顶多就是O(n2) ,就是暴力穷举每个区间,再直 ...
- D. Powerful array 离线+莫队算法 给定n个数,m次查询;每次查询[l,r]的权值; 权值计算方法:区间某个数x的个数cnt,那么贡献为cnt*cnt*x; 所有贡献和即为该区间的值;
D. Powerful array time limit per test seconds memory limit per test megabytes input standard input o ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 7687 Solved: 3516[Subm ...
- Bzoj 2038---[2009国家集训队]小Z的袜子(hose) 莫队算法
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色 ...
- 莫队算法 2038: [2009国家集训队]小Z的袜子(hose)
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2038 2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 ...
- BZOJ-2038 小Z的袜子(hose) 莫队算法
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MB Submit: 5573 Solved: 2568 [Subm ...
- 【BZOJ】2038: [2009国家集训队]小Z的袜子(hose)(组合计数+概率+莫队算法+分块)
http://www.lydsy.com/JudgeOnline/problem.php?id=2038 学了下莫队,挺神的orzzzz 首先推公式的话很简单吧... 看的题解是从http://for ...
- bzoj 2038 莫队算法
莫队算法,具体的可以看10年莫涛的论文. 大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们 可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理 的 ...
随机推荐
- Django创建模型_模型层
1.在项目Mysite下创建应用bms 2.在bms下的models.py文件中创建模型 from django.db import models # Create your models here. ...
- wireshark 学习 3 display filter
过滤信息,得到想要的帧进行分析. http://www.networkcomputing.com/networking/wifi-troubleshooting-using-wireshark/155 ...
- 剑指Offer:字符串排列【38】
剑指Offer:字符串排列[38] 题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bc ...
- 使用valgrind进行内存泄漏和非法内存操作检测
valgrind是一个强大的工具,最常用的功能是用它来检测内存泄漏和非法内存的使用.要想让valgrind报告的更加细致,请使用-g进行编译. 基本命令如下: $ valgrind --tool=me ...
- BZOJ 2142 礼物 数论
这道题是求组合数终极版. C(n,m) mod P n>=1e9 m>=1e9 P>=1e9且为合数且piqi<=1e5 拓展lucas定理. 实际上就是一点数论小知识的应用. ...
- git 生成patch和应用patch【转】
本文转载自:http://www.jianshu.com/p/814fb6606734 1.在git源码目录下执行 1.1.两个commit间的修改(包含两个commit) git format-pa ...
- loj#2269. 「SDOI2017」切树游戏
还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...
- 部署nginx支持lua
nginx yum -y install gcc pcre pcre-devel openssl openssl-devel GeoIP GeoIP-devel lua lua-develwget ...
- JavaScript(3)
var a=90; switch(a){ case "890": window.alert("ok"); break; case 90: window.aler ...
- c++迷宫小游戏
c++迷宫小游戏 一.总结 一句话总结: 显示:根据map数组输出图像 走动:修改map数组的值,每走一步重新刷新一下图像就好 1.如果走函数用z(),出现输入s会向下走多步的情况,原因是什么? 向下 ...