ICPC2020昆明 Cities

发布时间 2023-03-25 22:40:03作者: StkOvflow

原题链接

题目简述

\(\qquad\)给定一串数字,对于一串连续的数字,可以将它们染色成任意数字,问最少要多少次才能把这串数字全部染成同种颜色。

思路解析

\(\qquad\)我们可以对题目进行一下转化:所有数字全部染成同种颜色意味着相邻异色数对的数量为 \(0\),那我们每次对整段的区间染色,只有以下两种情况:

1 ->

......... a b b b b a .............

\(\qquad\)当这个区间的左右端点再向外扩张 \(1\) 位的时候,如果左右的数字相同,那么将 \(bbbb\) 这一段染色全部染成 \(a\) 将会减少 \(2\) 对异色对(分别是左边的 \((a, b)\) 和右边的 \((b, a)\)),我们称呼这种情况下的 \(bbbb\) 这段为被夹着的区间

2 ->

......... a b b b b c .............

\(\qquad\)当这个区间的左右端点再向外扩张 \(1\) 位的时候,如果左右的数字不同,那么将 \(bbbb\) 这一段染色全部染成 \(a\) 将会减少 \(1\) 对异色对,染成 \(c\) 也同理。

\(\qquad\) 接下来我们考虑一下极端的情况,也就是整个区间所有数字都不同,这种情况显然有n-1个异色对,由于没有同色的区间,所以一次只能消除 \(1\) 对,需要 \(n - 1\) 次操作。

\(\qquad\)然后我们可以统计被夹着的区间总数,然后用极端情况减去它就可以了

状态表示

\[f[l][r]表示[l, r]这段区间的所有颜色各自被夹着的区间总数的最大值 \]

解释:这样是为了选择最佳的颜色来染色。

状态转移

对于 \([l,r]\) 间没有能够与 \(l\) 的颜色配对的,直接跳过, \(f[l][r] = f[l+1][r]\)
对于有能与 \(l\) 的颜色配对的,找出所有的配对点(设为 \(m\) ),并分成三部分:
\(\qquad1.\) \([l,m]\) 之间有 \(1\) 个被夹住的区间
\(\qquad2.\) \([l+1,m-1]\),继承 \(l\)\(m\) 之间的答案
\(\qquad3.\) \([m, r]\),后半部分的答案,值得一提的是应该用 \(m\) 而非 \(m + 1\) 是因为 \(m\) 点可以二次利用,同时夹住两个区间。

解题流程

  1. 去重+处理出每个数下一个相等的数的下标,这里可以采用倒序处理的方式,具体如下。
for (int i = n; i; i -- ) {
	nxt[i] = pos[a[i]];
	pos[a[i]] = i;
}

pos保存的是每个数最后出现的下标
2. 开始DP,这里采用记搜
3. 输出答案

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 5010;
int f[N][N], a[N], n, T;
int nxt[N], pos[N];

int dp(int l, int r) {
	int &v = f[l][r];
	if (~v) return v;

	if (l >= r) return v = 0;
	v = dp(l + 1, r);

	int x = nxt[l];
	while (x <= r) {
		v = max(v, dp(l + 1, x - 1) + 1 + dp(x, r));
		x = nxt[x];
	}

	return v;
}

int main() {
	scanf("%d", &T);

	while (T -- ) {
		scanf("%d", &n);
		for (int i = 1; i <= n; i ++ ) pos[i] = n + 1;

		for (int i = 1; i <= n; i ++ ) {
			scanf("%d", &a[i]);
			if (a[i] == a[i - 1]) -- i, -- n;
		}
		for (int i = n; i; i -- ) {
			nxt[i] = pos[a[i]];
			pos[a[i]] = i;
		}

		for (int i = 1; i <= n; i ++ ) 
			for (int j = i; j <= n; j ++ ) f[i][j] = 0;

		memset(f, -1, sizeof f);
		printf("%d\n", n - 1 - dp(1, n));		
	}
    
    return 0;
}