专栏文章

题解:CF1630C Paint the Middle

CF1630C题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@miqf1sts
此快照首次捕获于
2025/12/04 03:44
3 个月前
此快照最后确认于
2025/12/04 03:44
3 个月前
查看原文

题意

给出一个长度为 nn 的序列 aa
还有一个初始为 00 的数组 cc
可以执行以下操作任意次:
选择三个元素 ii, jjkk1i<j<kn1 \leq i < j < k \leq n)。
条件:ci=cj=ck=0c_i=c_j=c_k=0ai=aka_i=a_k
效果:cj=1c_j=1
求操作后 i=1nci\sum\limits_{i=1}^n{c_i} 的最大值。

做法

一眼 DP
fif_i 表示区间 11ii 的没有贡献的数的个数,lstilst_i 表示元素 ii 第一次在 aia_i 中的下标。
初始化,f1=1f_1=1,因为第一个怎么操作都不可能有贡献。
对于每一个 ii,他可以把 lstai+1lst_{a_i}+1i1i-1 赋值,我们枚举 jj,其中 min(lstai,i1)ji1\min(lst_{a_i},i-1)\leq j \leq i-1,考虑将 j+1j+1i1i-1 赋值。所以 fi=fj+1f_i=f_j+1,这个 +1+1 是算上 ii 本身无法赋值。
那么 DP 方程式也就呼之欲出:
fi=minj=min(lstai,i1)i1fj+1f_i=\min\limits_{j=\min(lst_{a_i},i-1)}^{i-1}f_j+1
可这 n2n^2 的时间复杂度肯定过不了,用个线段树维护一下区间最小值就行了。
做蓝题的人应该没有不会线段树吧。
但是,有人要问了,如果 lstailst_{a_i}cc11 你都不知道那不是出锅了吗。
表面上来看,这样的问题确实存在,看似不可做,但仔细一想就可发发现,你总能改变赋值顺序来做到理想的贡献(手模几个样例理解更深)。

Code

CPP
#include<bits/stdc++.h>
#define ls(a) a<<1
#define rs(a) a<<1|1
using namespace std;
const int MAXN=1e6+10;
const int INF=1e9+7;
int n,g,a[MAXN],tree[MAXN],lst[MAXN];
//----------------线段树板子(求最小值)------------- 
void push_up(int x){
	tree[x]=min(tree[rs(x)],tree[ls(x)]);
}
void build(int x,int l,int r){
	if(l==r){
		tree[x]=INF;
		return;
	} 
	int mid=(l+r)>>1;
	build(ls(x),l,mid);
	build(rs(x),mid+1,r);
	push_up(x);
}
void update(int ql,int qr,int l,int r,int x,int k){
    if(ql<=l&&r<=qr){
    	tree[x]=min(tree[x],k);
        return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid) update(ql,qr,l,mid,ls(x),k);
    if(qr>mid) update(ql,qr,mid+1,r,rs(x),k);
    push_up(x);
}
int query(int ql,int qr,int l,int r,int x){
    int ans=INF;
    if(ql<=l&&r<=qr) return tree[x];
    int mid=(l+r)>>1;
    if(ql<=mid) ans=min(ans,query(ql,qr,l,mid,ls(x)));
    if(qr>mid) ans=min(ans,query(ql,qr,mid+1,r,rs(x)));
    return ans;
}
signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=n;i>=1;i--) lst[a[i]]=i;
	build(1,1,n),update(1,1,1,n,1,1);//初始化,第一个肯定没贡献 
	for(int i=2;i<=n;i++) g=query(min(lst[a[i]],i-1),i-1,1,n,1)+1,update(i,i,1,n,1,g);
	//DP
	printf("%d",n-g);//答案为:总的-没贡献的 
	return 0;
}

完结散花

评论

3 条评论,欢迎与作者交流。

正在加载评论...