hdu 5381 The sum of gcd 莫队算法+区间gcd
来源:互联网 发布:软件六大质量特性 编辑:程序博客网 时间:2024/05/20 16:44
题意:
略
思路:
杰哥说这种题他都做烂了。。。。orz
对于每个a[i]值,我们处理出以a[i]为起点,分别往左边和往右边的gcd区间的情况(gcd区间个数不会超过log(a[i])个,简单解释就是gcd相同的可以合并,且随着区间扩大,若gcd值不同,则每次至少除以2)。
a[i+1]的gcd区间可以由a[i]的情况推出,遇到可以合并的区间(gcd相等)就合并掉。
例如 2 3 3 6 5序列(以往左边gcd区间为例)
a[1] = 2:[1, 1]->2
a[2] = 3:[1, 1]->1,[2, 2]->3
a[3] = 3:[1, 1]->1,[2, 3]->3
a[4] = 6:[1, 1]->1,[2, 3]->3,[4, 4]->6//[2,3]->3表示这个区间任意一个a[i]到a[4]的区间gcd都等于3
a[5] = 5:[1, 4]->1,[5, 5]->5
(程序中区间顺序是倒过来存储的,这里只是为了方便阅读而写成这样)
最后套用莫队算法,莫队转移时间复杂度为logn
总的复杂度O(nsqrt(n)logn)
code:
#include <bits/stdc++.h>using namespace std;const int N = 1e4+5;typedef long long LL;int n, m;int block;int a[N];LL ans[N];struct PP { int l, r; int id; bool operator < (const PP &cmp) const { if(l/block == cmp.l/block) return r < cmp.r; return l/block < cmp.l/block; }}q[N];int gcd(int a, int b) { return b?gcd(b, a%b):a;}struct He { int idx;//存区间的下标 LL g;//存区间的gcd值};vector <He> vl[N], vr[N];void preDeal() {//left//推出左区间gcd的情况 for(int i = 1;i <= n; i++) { if(i == 1) vl[i].push_back((He){i, a[i]});//第1个点自己作为区间 else { int curg = a[i];//当前的gcd值 int l = i; for(auto &it:vl[i-1]) { int tmp = gcd(it.g, curg); if(tmp != curg)//若gcd不相等,说明这个区间不能和下个区间合并,就可以保存起来了 vl[i].push_back((He){l, curg}); curg = tmp, l = it.idx; } vl[i].push_back((He){l, curg});//把最后一个区间也放进去。 } }//right//推出右区间gcd情况 for(int i = n;i >= 1; i--) { if(i == n) vr[i].push_back((He){i, a[i]});//第n个点肯定是自己作为一个区间 else { int curg = a[i]; int r = i; for(auto &it:vr[i+1]) { int tmp = gcd(it.g, curg); if(tmp != curg) vr[i].push_back((He){r, curg}); curg = tmp, r = it.idx; } vr[i].push_back((He){r, curg}); } }}void solve() { for(int i = 1;i <= n; i++) vl[i].clear(), vr[i].clear(); block = (int)sqrt(n); sort(q, q+m); preDeal();//莫队算法 int l = 1, r = 0; LL res = 0; for(int i = 0;i < m; i++) { while(r < q[i].r) { r++; int tr = r; for(auto &it:vl[r]) { if(it.idx >= l) {//区间的idx值比当前的l值要大,说明这整个区间都是符合的,个数减一下就出来了 res += (tr-it.idx+1)*it.g;//下标的计算最好可以自己想仔细点。 tr = it.idx-1; } else {//到头了,只能取区间里某一部分。 res += (tr-l+1)*it.g; break; } } } while(r > q[i].r) { int tr = r; for(auto &it:vl[r]) { if(it.idx >= l) { res -= (tr-it.idx+1)*it.g; tr = it.idx-1; } else { res -= (tr-l+1)*it.g; break; } } r--; } while(l > q[i].l) { l--; int tl = l; for(auto &it:vr[l]) { if(it.idx <= r) { res += (it.idx-tl+1)*it.g; tl = it.idx+1; } else { res += (r-tl+1)*it.g; break; } } } while(l < q[i].l) { int tl = l; for(auto &it:vr[l]) { if(it.idx <= r) { res -= (it.idx-tl+1)*it.g; tl = it.idx+1; } else { res -= (r-tl+1)*it.g; break; } } l++; } ans[q[i].id] = res; } for(int i = 0;i < m; i++) printf("%I64d\n", ans[i]);}int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 1;i <= n; i++) scanf("%d", &a[i]); scanf("%d", &m); for(int i = 0;i < m; i++) scanf("%d%d", &q[i].l, &q[i].r); for(int i = 0;i < m; i++) q[i].id = i; solve(); } return 0;}
0 0
- hdu 5381 The sum of gcd 莫队算法+区间gcd
- HDU 5381(The sum of gcd-莫队算法解决区间段gcd的和)
- HDU 5381 The sum of gcd 询问区间内所有子区间的GCD和 [莫队算法]
- HDU 5381The sum of gcd 莫队算法
- 莫队算法,gcd(The sum of gcd,HDU 5381)
- HDU 5381 The sum of gcd 莫队暴力
- HDOJ 5381 The sum of gcd 莫队算法
- hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法
- HDU 5381 The sum of gcd(数论+莫队算法)
- 莫队算法 区间Gcd Hdu 5381
- HDU 5381 The sum of gcd
- hdu 5381 The sum of gcd
- hdu 5381 The sum of gcd
- HDU 5381The sum of gcd
- HDU 5381 The sum of gcd
- HDU 5381 The sum of gcd
- HDU 5381 The sum of gcd
- hdu 5381 The sum of gcd(线段树+gcd)
- KMP算法详解
- JQuery中wrap,wrapAll,wrapInner的区别
- UNIX环境高级编程之第4章:文件和目录
- 阿里巴巴产品实习生N天
- shape和selector的结合使用
- hdu 5381 The sum of gcd 莫队算法+区间gcd
- coj 1586: 分奖金
- CrossApp 项目导入Eclipse的生成Android客户端
- HDU 1873 看病要排队 (优先队列)
- Radar Installation
- Caffe学习:pycaffe接口配置
- Nginx模块开发(4)————使用subrequest访问第三方服务
- Android dx工具错误 解决
- 博客的开始