题目


题目大意:

给你一个等差序列,每次查询一段区间[l,r][l,r][l,r]的答案。 显然这是典型的不带修改的区间询问类问题,我们可以考虑用莫队算法去解决。


解题思路:

接下来看怎么递推[l,r][l,r][l,r]到[l−1,r][l-1,r][l−1,r],[l,r+1][l,r+1][l,r+1]的关系

首先对区间的询问是: 每次 任选aia_iai​,kkk,把aiaiai删掉,如ai+k==aia_{i+k}==a_{i}ai+k​==ai​则一直删下去,也就是把值相等,且下标形成等差数列的一列数删掉, 余下的数重新排列。

问你删除完整个数列的最少操作数

显然,第一次删掉后重排的话,我们肯定可以把所有数排成公差为1的一个个等差数列。

  • 所以其实 询问的意思就是: 如果第一次能找到一个数值,其所有出现的数的下标都形成等差数列(可以一次性删除),那么之后的操作步数实际就是 数值的种类数-1+1。
    因此 答案是 总种类数;

  • 如果第一次找不到 一个数满足 所有出现的数的下标都形成等差数列 则答案就是 总的种类数+1

  • 转移的话,需要预处理两个数组, fl[i]和fr[i],fl[i]表示i位置往左找,第一个使得a[i]a[i]a[i]不满足等差数列的位置,fr同理。

根据以下递推式:

inline void init() {for(int i = 1; i <= n; ++ i) {int p = arr[i];mp[p] = 1;pre[i] = last[p]; // 前驱last[p] = i;if(pre[i] - pre[pre[i]] == i - pre[i] || pre[pre[i]] == 0)fl[i] = fl[pre[i]];else fl[i] = pre[pre[i]];}for(auto it : mp) last[it.first] = n + 1;fr[n+1] = n+1;bak[0] = n+1;bak[n+1] = n+1;for(int i = n; i >= 1; -- i) {int p = arr[i];bak[i] = last[p]; // 后继last[p] = i;if(bak[bak[i]] - bak[i] == bak[i] - i || bak[bak[i]] == n + 1) fr[i] = fr[bak[i]];else fr[i] = bak[bak[i]];}
}

预处理完后,
按照莫队算法,如果上一次区间为[l,r][l,r][l,r],那么下一次要add一个数的话,
如果AddAddAdd的数第一次出现,则kind++, 且num_dengcha++

否则,看该数的加入是否会导致 num_dengcha减少。

即:if(fl[i]>=x&&fl[pre[i]]<x) dengcha–; 之前是等差,现在不是等差

如果是SubSubSub的话,

如果这个数只有一个,则显然kind–,num_dengcha–;

否则,看该数的减少会不会导致 num_dengcha的增加

即:if (fr[bak[i]]>R&&fr[i]<=R) dengcha++;

好了,接下来按照套路写莫队就好了


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
int n, m, arr[maxn];
int fl[maxn], fr[maxn];
int pre[maxn], bak[maxn], last[maxn];
unordered_map<int,bool> mp;
inline void init() {for(int i = 1; i <= n; ++ i) {int p = arr[i];mp[p] = 1;pre[i] = last[p];last[p] = i;if(pre[i] - pre[pre[i]] == i - pre[i] || pre[pre[i]] == 0)fl[i] = fl[pre[i]];else fl[i] = pre[pre[i]];}for(auto it : mp) last[it.first] = n + 1;fr[n+1] = n+1;bak[0] = n+1;bak[n+1] = n+1;for(int i = n; i >= 1; -- i) {int p = arr[i];bak[i] = last[p];last[p] = i;if(bak[bak[i]] - bak[i] == bak[i] - i || bak[bak[i]] == n + 1) fr[i] = fr[bak[i]];else fr[i] = bak[bak[i]];}// for(int i = 1; i <= n; ++ i)//   cout << fl[i] << " \n"[i == n];// for(int i = 1; i <= n; ++ i)//   cout << pre[i] << " \n"[i == n];// for(int i = 1; i <= n; ++ i) //   cout << fr[i] << " \n"[i == n];// for(int i = 1; i <= n; ++ i)//   cout << bak[i] << " \n"[i == n];
}struct node {int l, r, id;int b;
}q[maxn];bool cmp1(node x,node y) {return x.b^y.b?x.b<y.b:x.b&1?x.r<y.r:x.r>y.r;
}
int ans[maxn], res = 0, is;
int cnt[maxn];
inline void Add(int u, bool lorr, int i) {if(++ cnt[arr[u]] == 1) res ++, is ++;else {if(lorr) {// 这是判断是左右指针哪个在移动if(fr[bak[u]] > i && fr[u] <= i) is --; //之前是等差,现在不是等差, } else {if(fl[pre[u]] < i && fl[u] >= i) is --;}}
}inline void Sub(int u, bool lorr, int i) {if(-- cnt[arr[u]] == 0) res --, is --;else {if(lorr) {// 这是判断是左右指针哪个在移动if(fr[bak[u]] > i && fr[u] <= i) is ++;} else {if(fl[pre[u]] < i && fl[u] >= i) is ++;}}
}int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;int block = 500;for(int i = 1; i <= n; ++ i) cin >> arr[i];init();cin >> m;for(int i = 1; i <= m; ++ i) {int l, r;cin >> l >> r;q[i] = {l,r,i,(l-1)/block+1};}sort(q+1,q+1+m,cmp1);int l = 1, r = 0;for(int i = 1; i <= m; ++ i) {while(q[i].l < l) Add(--l,1,r);// 上个区间的rwhile(q[i].r > r) Add(++r,0,l);// 上个区间的lwhile(q[i].l > l) Sub(l++,1,r);while(q[i].r < r) Sub(r--,0,l);ans[q[i].id] = res - (is!=0) + 1;}for(int i = 1; i <= m; ++ i) cout << ans[i] << "\n";return 0;
}
/*
10
2 1 3 3 3 3 1 3 1 1
1
4 8
*/

莫队 ---- CF 135D. Jeff and Removing Periods (等差数列预处理 + 莫队)相关推荐

  1. 【2011年全国试题3】已知循环队列存储在一维数组A[0…n-1],且队列非空时,front和rear分别指向队头元素和队尾元素。若初始时队列为空,且

    [2011年全国试题3]已知循环队列存储在一维数组A[0-n-1],且队列非空时,front和rear分别指向队头元素和队尾元素.若初始时队列为空,且要求第一个进入队列的元素存储在A[0]处,则初始时 ...

  2. 以域变量rear和length分别指示循环队列中队尾元素的位置和内含元素的个数。给出队满条件和相应的如对和出队算法。

    以域变量rear和length分别指示循环队列中队尾 元素的位置和内含元素的个数.给出队满条件和相应的如对和出队算法. /* 以域变量rear和length分别指示循环队列中队尾 元素的位置和内含元素 ...

  3. 习题 3.25 两个乒乓球队进行比赛,各出3人。甲队为A、B、C3人,乙队为X、Y、Z3人。已抽签决定比赛名单。有人向队员打听比赛的名单,A说他不和X比,C说他不和X、Z比,请编程序找出3对赛手的名单

    C++程序设计(第三版) 谭浩强 习题3.25 个人设计 习题 3.25 两个乒乓球队进行比赛,各出3人.甲队为A.B.C3人,乙队为X.Y.Z3人.已抽签决定比赛名单.有人向队员打听比赛的名单,A说 ...

  4. *【HDU - 6333】Problem B. Harvest of Apples (莫队,逆元,组合数学)(这样预处理正确吗?)

    题干: There are nn apples on a tree, numbered from 11 to nn.  Count the number of ways to pick at most ...

  5. 莫队算法学习笔记(二)——带修莫队

    前言:什么是莫队 莫队算法,是一个十分优雅的暴力. 普通的莫队可以轻松解决一些离线问题,但是,当遇上了一些有修改操作的问题,普通莫队就无能为力了. 于是,改进后的莫队--带修莫队就这样产生了. L i ...

  6. 莫纳什大学计算机专业研究生在哪个校区,盘点莫纳什大学2019年计算机类硕士课程...

    莫纳什大学(Monash University),世界百强名校,澳大利亚名校联盟"八大名校"(Group of Eight)之一,五星级大学.1958年由国会建立,为纪念杰出的澳大 ...

  7. 莫纳什大学计算机硕士专业怎么样,澳大利亚留学:莫纳什大学计算机硕士的14个专业...

    澳大利亚莫纳什大学的计算机课程由Faculty of Information Technology(信息技术学院)提供,在授课型计算机硕士课程方面.目前主要提供以下14个方向的专业选择: Data M ...

  8. bzoj2038: [2009国家集训队]小Z的袜子(hose) 莫队

    Time Limit: 20 Sec Memory Limit: 259 MB Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小 ...

  9. P3246 [HNOI2016]序列 莫队 + ST表 + 单调栈

    传送门 文章目录 题意: 思路: Update 题意: 思路: 比较神奇的一个题,这里先介绍莫队的离线解法. 不难发现,用莫队来做最大的难点就是在进行区间移动的时候如何快速计算贡献. 比如[l,r]− ...

最新文章

  1. 【C++】函数指针的嵌套
  2. PostgreSQL的generate_series函数应用例子
  3. C++中对Mysql的操作函数可以参考以下blog中的内容
  4. js跳转页面时添加header_鸿蒙应用开发踩坑记之路由跳转
  5. Centos7 安装samba简单教程
  6. 存放有数组的list排序
  7. 1986暑假济南清北学堂腾飞营摸鱼记
  8. 线程池ThreadPoolExecutor的使用方法
  9. 2016030208 - sql50题练习题
  10. UCOS内核结构学习笔记
  11. LINUX 软件安装。
  12. CentOS 6.3最小化安装后,有些必备工作才可以正常使用
  13. 普林斯顿微积分读本06第五章--连续性
  14. 《精通javascript》-----------------------读书笔记
  15. excel函数去重_excel去重函数
  16. MS17010漏洞利用姿势
  17. mysql怎么读取数据,面试建议
  18. 魔域手游安卓修改服务器地址,魔域互通端游手游架设
  19. U系银河麒麟配置本地镜像源
  20. python如何写生日快乐说说_抖音上很火的生日句子,适合过生日发的高逼格

热门文章

  1. Redis中集合set数据类型(增加(添加元素)、获取(获取所有元素)、删除(删除指定元素))
  2. 汇编语言学习-寄存器(内存访问)
  3. Python网络爬虫之requests库Scrapy爬虫比较
  4. 如何利用K-Means将文件夹中图像进行分类?
  5. codeup:问题 D: 最短路径
  6. 基于网络监听方式的电子邮件实现基础
  7. 高通总裁:物联网和云计算正改变游戏规则
  8. hdu 5945 Fxx and game
  9. 【转】【iOS知识学习】_视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途...
  10. HTTP协议是无状态协议,怎么理解?