[CSP-S 2024] 染色

Yorg發表於2024-11-05

前言

很難蚌的一次考試, 很難確定是實力問題還是什麼

演算法

事實上是可以看出是 dp 題的
\(f_{i, j}\) 為考慮到 \(i\) 位的答案, 當前顏色為 \(j\), \(j \in {0, 1}\)
\(last_i\) 表示 \(i\) 位前第一個與 \(i\) 位顏色相同的

\(50 pts\)

  • 當前位置產生貢獻
    對於 \(f_{i, j}\) , 顯然從 \(last_i + 1\)\(i - 1\) , 有: 顏色為 ~\(j\)
    對於 \(50 pts\) 的做法, 這裡是可以預處理出每一個區間取一個值產生的貢獻, 具體的
for (int i = 1; i <= n; i++) 
{
	for (int j = i + 1; j <= n; j++) 
	{
		g[i][j] = g[i][j - 1];
		if (a[j] == a[j - 1]) g[i][j] += a[j];
	}
} 

\(O(n ^ 2)\)

\[f_{i, j} = f_{last_i, j} + a_i + g_{last_i + 1, i - 1} \]

  • 當前位置不產生貢獻
    顯然有

\[f_i, j = f_{i - 1, j} \]

\(50pts\) 程式碼

#include <bits/stdc++.h>

#define rint register int

using namespace std;

const int N = 2e3 + 5;

int n, T;
int a[N], lst[N];
int f[N], g[N][N], ans; 

signed main() 
{
	cin >> T;
	while (T--) 
	{
		cin >> n;
		memset(a, 0, sizeof a);
		memset(lst, 0, sizeof lst);
		memset(f, 0, sizeof f);
		memset(g, 0, sizeof g);
		for (rint i = 1; i <= n; i++) cin >> a[i];
		for (rint i = 1; i <= n; i++) 
		{
			for (rint j = i + 1; j <= n; j++) 
			{
				g[i][j] = g[i][j - 1];
				if (a[j] == a[j - 1]) g[i][j] += a[j];
			}
		} 
		for (rint i = 1; i <= n; i++) 
		{
			if (lst[a[i]] == 0) 
			{
				lst[a[i]] = i;
				f[i] = f[i - 1];
			} else 
			{
				f[i] = max(f[i - 1], max(f[lst[a[i]] + 1], f[lst[a[i]]]) + a[i] + g[lst[a[i]] + 1][i - 1] );
				lst[a[i]] = i;
			}
		}
		cout << f[n] << endl;
	}
	return 0;
}

正解

考慮最佳化
觀察到 \(g\) 陣列是完全沒有必要的
\(h_i = g_{1, i}\)
字首和處理即可

正解程式碼

略, 顯然非常好實現

總結

對於 dp 最佳化, 考慮建立輔助陣列, 再想辦法從輔助陣列的特殊性質下手進行最佳化
這是一種常見的套路