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 ...
随机推荐
- 跨域通信的解决方案JSONP
在web2.0时代,熟练的使用ajax是每个前端攻城师必备的技能.然而由于受到浏览器的限制,ajax不允许跨域通信. JSONP就是就是目前主流的实现跨域通信的解决方案. 虽然在在jquery中,我们 ...
- Educational Codeforces Round 24 A 水 B stl C 暴力 D stl模拟 E 二分
A. Diplomas and Certificates time limit per test 1 second memory limit per test 256 megabytes input ...
- Codeforces 578.C Weakness and Poorness
C. Weakness and Poorness time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- K8s仪表盘
{ "__inputs": [ { "name": "DS_TEST-ENVIORMENT-K8S", "label": ...
- jinja2 中的 Template 批量替换json字符串中的内容
项目中用到elasticsearch,使用Json格式查询方式,一个查询语句中有好几个地方需要替换,且替换的值都相同.最开始把json转为字符串发方式,利用format函数处理,发现再转回json时无 ...
- nova-conductor与AMQP(二)
源码版本:H版 一.首先看服务的启动脚本 /usr/bin/nova-conductor import sys from nova.cmd.conductor import main if __nam ...
- POJ 3348 Cows 凸包 求面积
LINK 题意:给出点集,求凸包的面积 思路:主要是求面积的考察,固定一个点顺序枚举两个点叉积求三角形面积和除2即可 /** @Date : 2017-07-19 16:07:11 * @FileNa ...
- 《HTML5编程之旅》系列二:Communication 技术初探
本文主要探讨用于构建实时跨源通信的两个模块:跨文档消息通信(Cross Document Messaging)和XMLHttpRequestLevel2.通过这两个模块,我们可以构建不同域间进行安全 ...
- Js冒泡事件详解及阻止
Js冒泡机制是指如果某元素定义了事件A,如click事件,如果触发了事件之后,没有阻止冒泡事件,那么事件将向父级元素传播,触发父类的click函数. 如下例所示: <html> & ...
- 20155117王震宇 实验三 敏捷开发与XP实践 实验报告
实验内容 XP基础 XP核心实践 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实 ...