题目
n(3<=n<=2e5)个元素,第i个元素有两个值ai(1<=ai<=n)和ci,一开始所有ci均为0,
每次操作,你可以选择三个不同的下标i<j<k,ci=cj=ck=0且ai=ak,然后把cj置为1
允许操作任意次,求最大的sumc之和
思路来源
wyn
题解
显然,对于每个值ai来说,只有最初和最末两个位置有用,对应一条线段
线段内的值,都可以被这条线段内的两个端点搞成1,
操作一:被完整包含的线段是没有用的,可以被删除,
例如,[1,5]包含了[2,4],此时删除[2,4]
操作二:经历操作一后,只有若干段相交的区间了,
此时,再删掉被一前一后完全包含的区间
例如,[1,5][2,6][3,7],[2,6]被一前一后完全包含,此时删[2,6]
最终得到的区间,是不可被再删除的最少个数的区间
假设最后某个段是x个区间前后交在一起的,
则这段内共有x+1个点不可被删除,
例如,[1,5]和[3,7]两个区间套在一起,[1,7]共有3个点不可被删,
统计答案即可
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,a[N],fi[N],las[N],c,x,ans;
struct node{
int l,r;
}e[N];
bool operator<(node a,node b){
if(a.l!=b.l)return a.l<b.l;
return a.r>b.r;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(!fi[a[i]])fi[a[i]]=i;
las[a[i]]=i;
}
for(int i=1;i<=n;++i){
if(fi[i])e[++c]={fi[i],las[i]};
}
sort(e+1,e+c+1);
for(int i=1;i<=c;){
int nowr=e[i].r,j=i;
e[++x]=e[i];
while(j+1<=c && e[j+1].l<=nowr){
if(e[j+1].r>nowr)e[++x]=e[j+1];//去掉被完整包含的线段,如:[1,5][2,4],删[2,4]
nowr=max(nowr,e[j+1].r);
j++;
}
i=j+1;
}
c=x;
for(int i=1;i<=c;){
int nowr=e[i].r,j=i,del=0;
while(j+1<=c && e[j+1].l<=nowr){
if(j+2<=c && e[j+2].l<=nowr)del++;//去掉被一前一后包含的线段,如:[1,5][2,6][3,7],删[2,6]
else nowr=max(nowr,e[j+1].r);
j++;
}
ans+=max(0,nowr-e[i].l+1-(j-i+1-del+1));//剩下j-i+1-del段 共有j-i+1-del+1个点不可删
i=j+1;
}
printf("%d\n",ans);
return 0;
}