题意:

给出 nnn 个数字,一共 qqq 次查询,每次询问一个 lll、rrr,查询区间 [l,r][l,r][l,r] 中有多少个不同的 gcdgcdgcd,其中一个子区间代表一个 gcdgcdgcd。(1≤n,q≤105,1≤ai≤106)(1\leq n,q\leq 10^5,1\leq a_i\leq 10^6)(1≤n,q≤105,1≤ai​≤106)


思路:

区间查询不同 gcdgcdgcd 的个数,这类题像一类套路问题,主要要抓住 gcdgcdgcd 的几个性质。

  • 固定右端点,移动左端点,gcdgcdgcd 的值从 ara_rar​ 不断变化,要么不变,要么至少除 222(因为 gcdgcdgcd 最小值为 222)。因此固定右端点之后,只会存在至多 logloglog 个不同的 gcdgcdgcd,我们对于相同的 gcdgcdgcd 仅保留最靠右的位置。
  • 因此对于每个右端点,我们记录一个 vectorvectorvector,存储对于这个右端点的所有不同的 gcdgcdgcd 值。我们可以根据 vector[i−1]vector[i-1]vector[i−1] 来更新 vector[i]vector[i]vector[i]。

处理完上述操作之后,我们得到了 n∗lognn*lognn∗logn 个 (l,r,gcd)(l,r,gcd)(l,r,gcd) 三元组,然后我们将所有查询按照右端点排序。

记录一个 pospospos,不断右移到查询的右端点位置,每次移动时将 vector[pos]vector[pos]vector[pos] 内的信息存储到树状数组中,即对于每个三元组 (l,pos,gcd)(l,pos,gcd)(l,pos,gcd),如果该 gcdgcdgcd 未出现过,则在树状数组的 lll 位置 +1+1+1,并设置 vis[gcd]=lvis[gcd]=lvis[gcd]=l。如果该 gcdgcdgcd 出现过,则比较 lll 是否比 vis[gcd]vis[gcd]vis[gcd] 更大,如果更大,则修改 gcdgcdgcd 在树状数组中的位置。上述操作即不断维护 gcdgcdgcd 最靠右的出现位置。然后对于每个查询,直接在树状数组中区间查询即可。


总结:

此题最关键的在于发现区间 gcdgcdgcd 不断除 222 的性质,然后将查询离线利用树状数组不断维护每个 gcdgcdgcd 最后出现的位置即可完成。


代码:

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a);
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define per(i,a,b) for(int i = a; i >= b; i--)
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef double db;
const int N = 1e6+100;
const db EPS = 1e-9;
using namespace std;void dbg() {cout << "\n";}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}int n,q,a[N],vis[N];
ll ans[N],c[N];
struct Node{int l,r,id;bool operator < (Node xx) const {return r < xx.r;}
}Q[N];
vector<pair<int,int> > base[N];inline int lowbit(int x) {return x&(~x+1);}
inline void update(int x,ll v) {for(;x<=n;x+=lowbit(x)) c[x] += v;}
inline ll ask(int x){ll tp = 0;while(x) tp += c[x], x -= lowbit(x);return tp;
}int gcd(int a,int b){return b == 0 ? a:gcd(b,a%b);
}int main()
{while(~scanf("%d%d",&n,&q)){rep(i,1,n) scanf("%d",&a[i]);rep(i,1,n) base[i].clear();rep(i,0,n) c[i] = 0;//更新每个点的vectorrep(i,1,n){base[i].push_back(make_pair(i,a[i])); vis[a[i]] = 1;for(auto &v:base[i-1]){int tp = gcd(v.second,a[i]);if(!vis[tp]){base[i].push_back(make_pair(v.first,tp));vis[tp] = 1;}}for(auto &v:base[i])vis[v.second] = 0;}rep(i,1,q) scanf("%d%d",&Q[i].l,&Q[i].r), Q[i].id = i;sort(Q+1,Q+1+q);int pos = 0;rep(i,1,q){while(pos <= Q[i].r){for(auto &v:base[pos]){int hp = v.first;if(hp > vis[v.second]){if(vis[v.second]) update(vis[v.second],-1);vis[v.second] = hp;update(vis[v.second],1);}}pos++;}ans[Q[i].id] = ask(Q[i].r)-ask(Q[i].l-1);}rep(i,1,q) printf("%lld\n",ans[i]);memset(vis,0,sizeof vis);}return 0;
}

【HDU 5869】Different GCD Subarray Query【区间不同 gcd 个数】相关推荐

  1. HDU 5869 Different GCD Subarray Query 树状数组 + 一些数学背景

    http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:给定一个数组,然后给出若干个询问,询问[L, R]中,有多少个子数组的gcd是不同的. 就是[L, ...

  2. [HDOJ5869] Different GCD Subarray Query(RMQ,树状数组,离线)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5869 题意:n个数,q次询问,问区间内gcd不同值的个数. 和dquery那道题一样,也是离线的做法. ...

  3. 【HDU - 5869】Different GCD Subarray Query(思维,数学,gcd,离线处理,查询区间不同数,树状数组 或 二分RMQ)

    题干: This is a simple problem. The teacher gives Bob a list of problems about GCD (Greatest Common Di ...

  4. 2016 大连网赛---Different GCD Subarray Query(GCD离散+树状数组)

    题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5869 Problem Description This is a simple probl ...

  5. HDU 5869.Different GCD Subarray Query-区间gcd+树状数组 (神奇的标记右移操作) (2016年ICPC大连网络赛)...

    树状数组... Different GCD Subarray Query Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/6 ...

  6. HDU - 5919 Sequence II——主席树+区间种类++逆序建树

    [题目描述] HDU - 5919 Sequence II [题目分析] 题目给定一个数组,每次查询一个区间,找出区间内不同数字的个数x,然后输出按出现顺序第x/2向上取整个数字的位置. 按照要求,我 ...

  7. HDU 5693:D Game(区间DP)

    D Game Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Sub ...

  8. 树状数组求逆序对_区间和的个数(树状数组)

    327. 区间和的个数 给定一个整数数组 nums,返回区间和在 [lower, upper] 之间的个数,包含 lower 和 upper. 区间和 S(i, j) 表示在 nums 中,位置从 i ...

  9. zoj 2112 树状数组 套主席树 动态求区间 第k个数

    总算是把动态求区间第k个数的算法看明白了. 在主席树的基础上,如果有修改操作,则要通过套树状数组来实现任意区间求第k小的问题. 刚开始看不明白什么意思,现在有一点理解.树状数组的每个元素是一个线段树, ...

  10. python acm 素数个数_湘潭大学OJ-1098求区间内素数个数问题

    求区间内素数个数问题 题目描述 Description 给定两个非负整数a,b,其中0<= a,b<=1,000,000,请计算这两个数之间有多少个素数.限制:Time Limit : 1 ...

最新文章

  1. android fragmentpageradapter切换不更新,关于android:在FragmentPagerAdapter中更新当前片段...
  2. 亚马逊是如何进行软件开发的
  3. android wlan0 网卡过程,android WIFI网络驱动之wpa_supplicant程序详解
  4. JavaScript 技术篇-js检测原生对象类型实例演示,js的3种对象类型
  5. cks32和stm32_cks子,间谍,局部Mo子和短管
  6. 前端学习(740):函数返回值注意事项
  7. 20165302 学习基础和C语言基础调查
  8. connot+connect+mysql+127.0.0.1_无法远程连接 MySQL 的解决方法
  9. mysql linq 事务_一步一步学Linq to sql(七):并发与事务
  10. 思科CCNA电子教程
  11. 记一次基于公众号的微信H5开发项目(一)
  12. (毕业设计资料)基于单片机51单片机智能药盒控制系统设计
  13. C++操作图像、图片
  14. 包转发率交换容量详解
  15. Day 5 E. Arranging The Sheep
  16. 简单的小游戏,六步实现简单扫雷!(可玩)
  17. hive:条件:where and or
  18. Java面试题最新更新
  19. 2020全国大学生数学建模竞赛穿越沙漠第二问求解方法
  20. Java面试常见知识点总结

热门文章

  1. linux 平台安装ionic开发调试编译环境(Android)
  2. Django part 6 ---Static File
  3. C++对象数组的实例学习
  4. jquery实现点击元素,如果弹出层隐藏则显示,显示则隐藏
  5. STC学习:串口通信
  6. radar nyoj 287
  7. python圆周率计算_python圆周率计算(带进度条)
  8. phpstorm 正则匹配搜索_phpstorm 有哪些奇技淫巧?
  9. ipcfg报错_CentOS服务器安装Anaconda
  10. 简述java中类的构造方法_Java中类的构造方法