题目链接: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(莫队+区间等差数列更新)的更多相关文章

  1. CF&&CC百套计划3 Codeforces Round #204 (Div. 1) D. Jeff and Removing Periods

    http://codeforces.com/problemset/problem/351/D 题意: n个数的一个序列,m个操作 给出操作区间[l,r], 首先可以删除下标为等差数列且数值相等的一些数 ...

  2. Codeforces 617E XOR and Favorite Number莫队

    http://codeforces.com/contest/617/problem/E 题意:给出q个查询,每次询问区间内连续异或值为k的有几种情况. 思路:没有区间修改,而且扩展端点,减小端点在前缀 ...

  3. codeforces 220B . Little Elephant and Array 莫队+离散化

    传送门:https://codeforces.com/problemset/problem/220/B 题意: 给你n个数,m次询问,每次询问问你在区间l,r内有多少个数满足其值为其出现的次数 题解: ...

  4. Codeforces 666E E - Forensic Examination SA + 莫队 + 线段树

    E - Forensic Examination 我也不知道为什么这个复杂度能过, 而且跑得还挺快, 数据比较水? 在sa上二分出上下界, 然后莫队 + 线段树维护区间众数. #include< ...

  5. CodeForces - 617E XOR and Favorite Number 莫队算法

    https://vjudge.net/problem/CodeForces-617E 题意,给你n个数ax,m个询问Ly,Ry,  问LR内有几对i,j,使得ai^...^ aj =k. 题解:第一道 ...

  6. 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 ...

  7. XOR and Favorite Number CodeForces - 617E(前缀异或+莫队)

    题意原文地址:https://blog.csdn.net/chenzhenyu123456/article/details/50574169 题意:有n个数和m次查询,每次查询区间[l, r]问满足a ...

  8. Machine Learning CodeForces - 940F(带修改的莫队)

    题解原文地址:https://www.cnblogs.com/lujiaju6555/p/8468709.html 给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次 ...

  9. 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 ...

随机推荐

  1. 【状压DP】【CF8C】 Looking for Order

    传送门 Description 给你n个点,每次可以从起点到最多两个点然后回到起点.求经过每个点最少一次的最短欧氏距离和是多少 Input 第一行是起点的坐标 第二行是点的个数\(n\) 下面\(n\ ...

  2. MFC之ListCtrl动态添加按钮

    先上效果图: 图中用了一个CListCtrl插件,隐藏了网格线(LVS_EX_GRIDLINES). 添加了“删除”按钮(按钮上贴了图片),选中哪一行则显示在哪一行. 有两种方式创建按钮,一种是直接根 ...

  3. Codeforces 311.E Biologist

    E. Biologist time limit per test 1.5 seconds memory limit per test 256 megabytes input standard inpu ...

  4. poj1284 Primitive Roots

    Primitive Roots Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4775   Accepted: 2827 D ...

  5. 数据压缩算法之哈夫曼编码(HUFFMAN)的实现

    HUFFMAN编码可以很有效的压缩数据,通常可以压缩20%到90%的空间(算法导论).具体的压缩率取决于数据的特性(词频).如果采取标准的语料库进行编码,一般可以得到比较满意的编码结果(对不同文件产生 ...

  6. checkbox选择根据后台List数据进行回显

    需求:记住用户已经选择的 checkbox 选项,当用户再次对该 checkbox 进行选择操作时,应对该用户已经选择的 checkbox 选项进行选中操作. 示例代码: checkbox,js遍历后 ...

  7. Dubbo 的应用

    ---  用于大规模服务化,通过在消费方获取服务提供方的地址列表,实现负载均衡,减轻服务器压力. 最简单调用图 节点角色说明: l  Provider: 暴露服务的服务提供方. l  Consumer ...

  8. NOIP模拟5

    期望得分:100+100+100=300 实际得分:72+12+0=84 T1  [CQOI2009]中位数图 令c[i]表示前i个数中,比d大的数与比d小的数的差,那么如果c[l]=c[r],则[l ...

  9. Laravel是怎么实现autoload的?

    用了一阵Laravel后发现很少有include和require,觉得有点奇怪,思考Laravel是怎么完成文件导入的. 其实Laravel依旧还是用include或者require的,只是都写在一个 ...

  10. Flex布局(伸缩盒布局)

    Flexible Box是什么?Flexible意为可伸缩的,Box意为盒子,可以理解为一种新式的盒模型——伸缩盒模型.由CSS3规范提出,这是在原有的大家非常熟悉的block, inline-blo ...