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 ...
随机推荐
- Combining HTML5 Web Applications with OpenCV
The Web Dev Zone is brought to you by Stormpath—offering a pre-built Identity API for developers. Ea ...
- 20135239益西拉姆 Linux内核分析 汇编一个简单的c程序并分析其指令过程
益西拉姆+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 第一周linux内核分析 学习笔记 一.计算机 ...
- Hive(五)hive的高级应用
一.视图 视图:享用基本表的数据,不会生成另外一份数据创建视图:create view view_name as select * from carss;create view carss_view ...
- AtCoder Regular Contest 086 E - Smuggling Marbles(树形迭屁)
好强的题. 方案不好算,改成算概率,注意因为是模意义下的概率所以直接乘法逆元就好不要傻傻地开double. 设$f[i][d][0]$为第i个节点离d层的球球走到第i个点时第i个点没有球的概率, $f ...
- cmakelist 定义字符串,替换到脚本中。
cmake_minimum_required(VERSION 2.6 FATAL_ERROR) cmake_policy(VERSION 2.6) # . Project Name project(s ...
- HDU--2722
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2722 分析:简单最短路,读入数据烦. #include<iostream> #includ ...
- mysql命令修改登录用户密码
方法1: 用SET PASSWORD命令 首先登录MySQL. 格式:mysql> set password for 用户名@localhost = password(‘新密码’); 例子:my ...
- python---爬虫相关性能(各个异步模块的使用,和自定义异步IO模块)
一:线程池,进程池等相关文章了解 python---基础知识回顾(十)进程和线程(py2中自定义线程池和py3中的线程池使用) python---基础知识回顾(十)进程和线程(协程gevent:线程在 ...
- 【BZOJ】2165: 大楼
[题意]从第0层开始有无穷层,每层有n个房间,给定矩阵A,A[i][j]表示从第x层的房间 i 可以跳到第x+A[i][j]层的房间 j (x任意),A[i][j]=0表示不能跳.初始在第0层第1个房 ...
- 【BZOJ】2693: jzptab 莫比乌斯反演
[题意]2154: Crash的数字表格 莫比乌斯反演,多组询问,T<=10000. [算法]数论(莫比乌斯反演) [题解]由上一题, $ans=\sum_{g\leq min(n,m)}g\s ...