Codeforces 351D Jeff and Removing Periods(莫队+区间等差数列更新)
题目链接:http://codeforces.com/problemset/problem/351/D
题目大意:有n个数,每次可以删除掉数值相同并且所在位置成等差数列的数(只删2个数或者只删1个数应该也是可以的),删掉这些数以后可以将剩下的数重新以任意顺序排列,称为一次操作。现在给出m个询问,每个询问一个区间[l,r],问删光区间[l,r]中的数最少需要的操作次数。
解题思路: 由于一次操作之后可以以任意顺序排序,所以可以把相同数字排成等差的以便删除,那接下来就只要判断这个区间还有几种数字,一种数字操作一次就可以了,这个用莫队就能很快解决。但是问题在于第一次操作能不能将其中一种数字删尽,也就是在未排序情况下该区间是否有一种数字是成等差数列的。可以通过设置两个数组fl[i],fr[i],让fl[i]记录往左a[i]第一次不成等差的位置,fr[i]记录往右a[i]第一次不成等差的位置。这样只要相应地对add(),remove()做出修改就可以更新一段区间内的等差数列的个数了。具体看代码。
还有我个人犯的几个小错误,注意一下:
①使用的l,r应当是当前的L,R而不是查询区间的l,r。
②一开始没把add,remove弄明白,remove(pos)里的pos是即将要去掉的那个位置,add(pos)里的pos是即将要加上的那个位置
③fl[i]应该处理成a[i]往左找第一个不成等差的位置,而不是最后一个成等差的位置(fr[i]同理),比如1 2 1 3 5这组对1操作就会出错
(把i<=n写出i<=m,题目前面十几个数据都是n=m,害我一下没看出来,我脑抽了竟然找了半天)
#include<iostream>
#include<algorithm>
#include<math.h>
#include<stdio.h>
#include<cstring>
using namespace std;
const int N=1e5+; int ans,unit,dc;
//fl[i]记录a[i]往左第一个不成等差的位置,fr[i]记录a[i]往右第一个不成等差的位置
//pre[i]记录从左往右前一个a[i]的位置,bak[i]记录从右往左前一个a[i]的位置,last[a[i]]记录a[i]最后出现位置
int a[N],cnt[N],res[N],pre[N],bak[N],last[N],fl[N],fr[N]; struct node{
int l,r;
int id;
}q[N]; bool cmp(node a,node b){
return a.l/unit==b.l/unit?a.r<b.r:a.l/unit<b.l/unit;
} void addl(int pos,int r){
cnt[a[pos]]++;
if(cnt[a[pos]]==){
dc++;
ans++;
} else if(fr[pos]<=r&&fr[bak[pos]]>r) dc--;//加上a[pos]之后不成等差&&加上之前成等差
} void removel(int pos,int r){
cnt[a[pos]]--;
if(cnt[a[pos]]==){
dc--;
ans--;
}
else if(fr[pos]<=r&&fr[bak[pos]]>r) dc++;//去掉a[pos]之前不成等差&&去掉之后成等差
} void addr(int pos,int l){
cnt[a[pos]]++;
if(cnt[a[pos]]==){
dc++;
ans++;
}
else if(fl[pos]>=l&&fl[pre[pos]]<l) dc--;//同理
} void remover(int pos,int l){
cnt[a[pos]]--;
if(cnt[a[pos]]==){
dc--;
ans--;
}
else if(fl[pos]>=l&&fl[pre[pos]]<l) dc++;
} int main(){
int n;
scanf("%d\n",&n);
unit=sqrt(n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
}
//预处理fl,fr
for(int i=;i<=n;i++){
pre[i]=last[a[i]];
last[a[i]]=i;
//从左往右,当a[i]个数小于等于两个时,左边界为0
if(pre[pre[i]]==)
fl[i]=;
else if(pre[pre[i]]-pre[i]==pre[i]-i)
fl[i]=fl[pre[i]];
else
fl[i]=pre[pre[i]];
}
//清空last
memset(last,,sizeof(last));
for(int i=n;i>=;i--){
bak[i]=last[a[i]];
last[a[i]]=i;
//从右往左,当a[i]个数小于等于两个时,右边界为n+1
if(bak[bak[i]]==)
fr[i]=n+;
else if(bak[bak[i]]-bak[i]==bak[i]-i)
fr[i]=fr[bak[i]];
else
fr[i]=bak[bak[i]];
} int m;
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
} sort(q+,q++m,cmp); int L=q[].l,R=L-;
for(int i=;i<=m;i++){
//注意传入add,remove的左右端点是L,R而不是q[i].l,q[i].r
while(L>q[i].l)
addl(--L,R);
while(L<q[i].l)
removel(L++,R);
while(R<q[i].r)
addr(++R,L);
while(R>q[i].r)
remover(R--,L);
if(dc>)
res[q[i].id]=ans;
else
res[q[i].id]=ans+;
} for(int i=;i<=m;i++){
printf("%d\n",res[i]);
}
}
Codeforces 351D Jeff and Removing Periods(莫队+区间等差数列更新)的更多相关文章
- CF&&CC百套计划3 Codeforces Round #204 (Div. 1) D. Jeff and Removing Periods
http://codeforces.com/problemset/problem/351/D 题意: n个数的一个序列,m个操作 给出操作区间[l,r], 首先可以删除下标为等差数列且数值相等的一些数 ...
- Codeforces 617E XOR and Favorite Number莫队
http://codeforces.com/contest/617/problem/E 题意:给出q个查询,每次询问区间内连续异或值为k的有几种情况. 思路:没有区间修改,而且扩展端点,减小端点在前缀 ...
- codeforces 220B . Little Elephant and Array 莫队+离散化
传送门:https://codeforces.com/problemset/problem/220/B 题意: 给你n个数,m次询问,每次询问问你在区间l,r内有多少个数满足其值为其出现的次数 题解: ...
- Codeforces 666E E - Forensic Examination SA + 莫队 + 线段树
E - Forensic Examination 我也不知道为什么这个复杂度能过, 而且跑得还挺快, 数据比较水? 在sa上二分出上下界, 然后莫队 + 线段树维护区间众数. #include< ...
- CodeForces - 617E XOR and Favorite Number 莫队算法
https://vjudge.net/problem/CodeForces-617E 题意,给你n个数ax,m个询问Ly,Ry, 问LR内有几对i,j,使得ai^...^ aj =k. 题解:第一道 ...
- CODEFORCES 340 XOR and Favorite Number 莫队模板题
原来我直接学的是假的莫队 原题: Bob has a favorite number k and ai of length n. Now he asks you to answer m queries ...
- XOR and Favorite Number CodeForces - 617E(前缀异或+莫队)
题意原文地址:https://blog.csdn.net/chenzhenyu123456/article/details/50574169 题意:有n个数和m次查询,每次查询区间[l, r]问满足a ...
- Machine Learning CodeForces - 940F(带修改的莫队)
题解原文地址:https://www.cnblogs.com/lujiaju6555/p/8468709.html 给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次 ...
- Codeforces Round #340 (Div. 2) E 莫队+前缀异或和
E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...
随机推荐
- 洛谷 P1023 税收与补贴问题 (2000NOIP提高组)
洛谷 P1023 税收与补贴问题 (2000NOIP提高组) 题意分析 一开始没理解题意.啰啰嗦嗦一大堆.看了别人的题解才明白啥意思. 对于样例来说,简而言之: 首先可以根据题目推算出来 28 130 ...
- Hbase(五) hbase内部原理
一.系统架构 客户端连接hbase依赖于zookeeper,hbase存储依赖于hadoop client: 1.包含访问 hbase 的接口, client 维护着一些 cache(缓存) 来加快对 ...
- Python new() 方法
什么是new方法 __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法. __new__()是在新式类中 ...
- eclipse快速复制一行代码(向下/向上)快捷键修改设置
eclipse快速复制一行代码(向下/向上)快捷键修改设置 2015年10月05日 17:46:57 xiaoguanglgc 阅读数:20906 标签: eclipse快速复制一行快捷键冲突英特尔 ...
- Swagger2 添加HTTP head参数,解决用户是token信息保留
转:http://blog.csdn.net/u014044812/article/details/71473226 大家使用swagger往往会和JWT一起使用,而一般使用jwt会将token放在h ...
- C++类成员空间分配和虚函数表
最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...
- eclipse+myeclipse 使用技巧备忘
myeclipse 导入多模块maven项目 https://blog.csdn.net/jack85986370/article/details/51371853 maven项目在eclipse的l ...
- Linux下打包压缩war和解压war包 zip和jar
============jar================= 把当前目录下的所有文件打包成game.warjar -cvfM0 game.war ./ -c 创建war包-v 显示过程信息 ...
- fmt:formatNumber use locale display negative currency in -$xxx.xx format in JSTL
First, we want to know our own locale,how to display the locale in a JSTL? <c:out value="${p ...
- [php]unset函数
unset($var); 释放一个变量空间 unset($var1, $var2...);释放多个变量空间 unset(var['数组元素内容']);释放数组元素 注意: 1.在函数内部释放全局变量和 ...