HDU 5869 树状数组+GCD性质的利用
2016-09-16 11:43
489 查看
当时我负责这题的,看到肯定能想到用线段树等数据结构处理,但是如果用一个节点保存对应区间不同的GCD个数,交叉在一起不能去重啊,
bd6e
于是就不会做了……太弱了。。。
百度了之后发现要离线处理……离线处理的好处是可以按顺序进行,防止前后的一些干扰
然后i从1-n遍历,每次算出a[i] 和a[i-1] 一直到a[1]能组成的GCD的个数,比如a[j]到a[i]组成了一个gcd,就把树状数组第j位+1,这里要注意的是,如果以前从j1-i1也组成了gcd,这个时候要比较J和J1哪个大,因为以后查询的时候是查询l到i,那么J肯定要取大的,靠近i,所以要把树状数组j1位-1,第j位+1,每次更新完i位后,树状数组从j = i到1存储了从a[j]到a[i]可以组成的gcd的个数,并且不与比j大的重复,于是每次询问可以在Logn中完成
而GCD的应用在于A分解质因数只有LOGA个,每次与一个不同的数求GCD,一定会约去一些质因数,所以最多求logA次
在程序中用了PRE把一样的数字跳过,只处理一次
这题还挺有技巧的。。这种离线处理的方法应该学一学,按照顺序处理……
代码是参考网上大神写的。。比较雷同……
bd6e
于是就不会做了……太弱了。。。
百度了之后发现要离线处理……离线处理的好处是可以按顺序进行,防止前后的一些干扰
然后i从1-n遍历,每次算出a[i] 和a[i-1] 一直到a[1]能组成的GCD的个数,比如a[j]到a[i]组成了一个gcd,就把树状数组第j位+1,这里要注意的是,如果以前从j1-i1也组成了gcd,这个时候要比较J和J1哪个大,因为以后查询的时候是查询l到i,那么J肯定要取大的,靠近i,所以要把树状数组j1位-1,第j位+1,每次更新完i位后,树状数组从j = i到1存储了从a[j]到a[i]可以组成的gcd的个数,并且不与比j大的重复,于是每次询问可以在Logn中完成
而GCD的应用在于A分解质因数只有LOGA个,每次与一个不同的数求GCD,一定会约去一些质因数,所以最多求logA次
在程序中用了PRE把一样的数字跳过,只处理一次
这题还挺有技巧的。。这种离线处理的方法应该学一学,按照顺序处理……
#include<bits/stdc++.h> using namespace std; const int maxn = 100010; const int maxnai = 1000010; int last[maxnai],a[maxn],pre[maxn],ans[maxn]; struct node { int l,id; }; vector<node> query[maxn]; struct bit { int tree[maxn]; int n; int lowbit(int x){ return (x & -x); } void init(int x) { memset(tree,0,sizeof(tree)); n = x; } void add(int x,int j) { while(x <= n){ tree[x] += j; x = x + lowbit(x); } } int sum(int x) { int ret = 0; while(x > 0){ ret += tree[x]; x = x - lowbit(x); } return ret; } }T; int gcd(int x,int y) { return (y == 0 ? x : (gcd(y,x%y))); } int main() { int n,q; while(scanf("%d %d",&n,&q) != EOF){ T.init(n); memset(last,0,sizeof(last)); for(int i = 1; i <= n; i++){ scanf("%d",&a[i]); query[i].clear(); } pre[1] = 0; for(int i =2; i <= n; i++){ if (a[i] == a[i - 1]) pre[i] = pre[i - 1]; else pre[i] = i - 1; } for(int i = 1; i <= q; i++){ int l,r; scanf("%d %d",&l,&r); query[r].push_back((node){l,i}); } for(int i = 1; i <= n; i++){ for(int j = i, x = a[j]; j >= 1 ; j = pre[j] ,x = gcd(x,a[j])){ if (j > last[x]){ if (last[x] != 0) T.add(last[x],-1); T.add(j,1); last[x] = j; } if (x == 1) break; } for(int j = 0; j < query[i].size(); j++){ //printf("%d %d %d %d\n",query[i][j].l,i,T.sum(i),T.sum(query[i][j].l - 1)); ans[query[i][j].id] = T.sum(i) - T.sum(query[i][j].l - 1); } } for(int i = 1; i <= q; i++){ printf("%d\n",ans[i]); } } return 0; }
代码是参考网上大神写的。。比较雷同……
相关文章推荐
- hdu-5869 Different GCD Subarray Query gcd预处理 + 树状数组 + 离线
- [区间GCD预处理 树状数组 离线] HDU 5869 Different GCD Subarray Query
- HDU 4417 超级马里奥 数据结构+利用树状数组进行快速统计+多维统计转换
- GCD and LCM+hdu+利用gcd和lcm的性质
- hdu 5869 RMQ+二分+离线树状数组
- [HDOJ5869] Different GCD Subarray Query(RMQ,树状数组,离线)
- HDU 2852 树状数组解决第K小数 附线段树解法
- hdu 2492【树状数组】
- hdu 1166 敌兵布阵 (树状数组)
- (树状数组) hdu 1166 敌兵布阵
- HDU_1541 Stars(树状数组)
- hdu 1394 树状数组版!!!
- hdu 3584 三维树状数组 很烦的说
- HDU 3525(树状数组求解LCS)
- HDU 1166 敌兵布阵【树状数组】
- HDU 1166 敌兵布阵【树状数组】
- hdu 3015【树状数组】
- HDU 3584 Cube 【三维树状数组】
- [hdu]1394 Minimum Inversion Number -- 暴力求逆序、树状数组求逆序、线段树求逆序、归并排序求逆序
- HDU 1892 See you~ 二维树状数组更新点查找区间