CF1479B2 Painting the Array II 题解 [DP+线段树]

Painting the Array II

Description:

​ Homer likes arrays a lot. Today he is painting an array \(a_1, a_2, \dots, a_n\) with two kinds of colors, white and black. A painting assignment for \(a_1, a_2, \dots, a_n\) is described by an array \(b_1, b_2, \dots, b_n\) that \(b_i\) indicates the color of \(a_i\) (\(0\) for white and \(1\) for black).

According to a painting assignment \(b_1, b_2, \dots, b_n\), the array a is split into two new arrays \(a^{(0)}\) and \(a^{(1)}\), where \(a^{(0)}\) is the sub-sequence of all white elements in \(a\) and \(a^{(1)}\) is the sub-sequence of all black elements in \(a\). For example, if \(a = [1,2,3,4,5,6]\) and \(b = [0,1,0,1,0,0]\), then \(a^{(0)} = [1,3,5,6]\) and \(a^{(1)} = [2,4]\).

The number of segments in an array \(c_1, c_2, \dots, c_k\), denoted \(\mathit{seg}(c)\), is the number of elements if we merge all adjacent elements with the same value in \(c\). For example, the number of segments in \([1,1,2,2,3,3,3,2]\) is \(4\), because the array will become \([1,2,3,2]\) after merging adjacent elements with the same value. Especially, the number of segments in an empty array is \(0\).

Homer wants to find a painting assignment \(b\), according to which the number of segments in both \(a^{(0)}\) and \(a^{(1)}\), i.e. \(\mathit{seg}(a^{(0)})+\mathit{seg}(a^{(1)})\), is as small as possible. Find this number.

中文题面:

​ 给你一个长度为 \(n\) 的数列 \(a\) ,让你将它划分为两个子序列。分别将两个子序列中的连续的相同元素合并为一个元素,每个子序列的价值为合并后的序列长度。请你最小化两个子序列的价值之和,输出这个最小价值。

Input:

​ The first line contains an integer \(n\) (\(1 \leq n \leq 10^5\)).

​ The second line contains \(n\) integers \(a_1, a_2, \dots, a_n\) (\(1 \leq a_i \leq n\)).

Output:

​ Output a single integer, indicating the minimal possible total number of segments.

Sample Input 1:

6
1 2 3 1 2 2

Sample Output 1:

4

Sample Input 2:

7
1 2 1 2 1 2 1

Sample Output 2:

2

Note:

​ In the first example, we can choose \(a^{(0)} = [1,1,2,2], a^{(1)} = [2,3]\) and \(\mathit{seg}(a^{(0)}) = \mathit{seg}(a^{(1)}) = 2\). So the answer is \(2+2 = 4\).

​ In the second example, we can choose \(a^{(0)} = [1,1,1,1], a^{(1)} = [2,2,2]\) and \(\mathit{seg}(a^{(0)}) = \mathit{seg}(a^{(1)}) = 1\). So the answer is \(1+1 = 2\).

Hint:

​ 对于\(100\%\)的数据,\(1 \leq n \leq 10^5,1 \leq a_i \leq n\)

​ 时间限制: \(2s\)

​ 空间限制: \(512M\)

题目分析:

​ 看到题目的第一眼想的是贪心,但是搞不出最优策略,于是转而选择DP。

​ 当然首先将 \(a\) 中连续的相同元素合并成一个元素方便考虑。

​ 设\(f_{i,j}\)表示当前一个序列以编号 \(i\) 来结尾,另一个序列以数字 \(j\) 来结尾(即 \(\exists k,st.1 \leq k < i,a_k=j\))

​ 那么有以下两种转移方式:

​ 1.\(f_{i,a_{i-1}}={\underset {1 \leq j \leq n}{\operatorname {min} }} \{f_{i-1,j} + (a_i \neq j)\}\)

​ 2.\(f_{i,j} = f_{i-1,j} + 1\)

​ 经观察,我们发现这就是个全局加,单点修改,全局查询,因此可以用线段树维护即可。

​ PS:其实可以不用线段树。。。随便搞个堆处理一下就行了。

​ 代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,tot,a[maxn],f[maxn<<2],tag[maxn<<2];
inline void pushdown(int now){
	tag[now<<1]+=tag[now],tag[now<<1|1]+=tag[now];
	f[now<<1]+=tag[now],f[now<<1|1]+=tag[now];tag[now]=0;
}
inline void pushup(int now){f[now]=min(f[now<<1],f[now<<1|1]);}
inline void modify(int now,int l,int r,int x,int v){
	if(l==r){f[now]+=v;return;}pushdown(now);int mid=l+r>>1;
	if(mid>=x) modify(now<<1,l,mid,x,v);else modify(now<<1|1,mid+1,r,x,v);pushup(now);
}
inline void updata(int now,int l,int r,int x,int v){
	if(l==r){f[now]=v;return;}pushdown(now);int mid=l+r>>1;
	if(mid>=x) updata(now<<1,l,mid,x,v);else updata(now<<1|1,mid+1,r,x,v);pushup(now);
}
inline void build(int now,int l,int r){
	if(l==r){if(l) f[now]=maxn;return;}int mid=l+r>>1;
	build(now<<1,l,mid),build(now<<1|1,mid+1,r),pushup(now);
}
inline int read(){
	int ret=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();return ret*f;
}
int main(){
	n=read();build(1,0,n);for(register int i=1;i<=n;i++){a[i]=read();if(a[i]!=a[i-1]) a[++tot]=a[i];}for(register int i=1;i<=tot;i++)
	{modify(1,0,n,a[i],-1);int x=f[1]+1;modify(1,0,n,a[i],1),tag[1]++,f[1]++,updata(1,0,n,a[i-1],x);}cout<<f[1]<<'\n';
	return 0;
}
posted @ 2021-02-08 10:32  OdtreePrince  阅读(240)  评论(1编辑  收藏  举报