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 ...
随机推荐
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
[BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...
- Last Position of Target
For a given sorted array (ascending order) and a target number, find the first index of this number ...
- 洛谷 P3241 [HNOI2015]开店 解题报告
P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...
- WebDriver的定位元素方法
如果把页面上的元素看作人的话,在现实世界如何找到某人呢?方法有三: 一.通过人本身的属性,例如他的姓名,手机号,身份证号,性别,这些可区别他人的属性.在web页面上的元素也有这些属性,例如,id.na ...
- C++之正则表达式20171121
准确来说,不论在C++或C中,只要在Linux系统中都可以使用本文讲诉的正则表达式使用方式. 一.Linux中正则表达式的使用步骤: 编译正则表达式 regcomp() 匹配正则表达式 regexec ...
- Codeforces Round #407 (Div. 2)A B C 水 暴力 最大子序列和
A. Anastasia and pebbles time limit per test 1 second memory limit per test 256 megabytes input stan ...
- AJAX 状态值与状态码详解
1- AJAX状态值与状态码区别 AJAX状态值是指,运行AJAX所经历过的几种状态,无论访问是否成功都将响应的步骤,可以理解成为AJAX运行步骤.如:正在发送,正在响应等,由AJAX对象与服务器交互 ...
- nginx 与 tomcat 组合搭建web服务
部分内容转自 http://www.cnblogs.com/naaoveGIS/ 1. Web服务 nginx是常用的web服务器,用于获取静态资源,类似的服务器还有apache. tomcat是基于 ...
- DELPHI中的快捷方式一览(完全版)
1.SHIFT+鼠标左键 先选中任一控件,按键后可选中窗体(选中控件后按Esc效果一样)2.Shift+F8 调试时弹出CPU窗口.3.Shift+F10 等于 ...
- 【NOI2017】游戏 2-sat算法
[题目]LibreOJ [题意]n场游戏,有三种车ABC,给定长度为n的字符串,'a'表示不能选A,'b''c'同理,'x'表示不限,至多d个'x'.有m个限制(i,hi,j,hj)表示如果第i场选择 ...