题解:P11233 [CSP-S 2024] 染色

本文仅供自我复习,一年后来看感觉写复杂了,懒得改了。

基本思路

错误的状态设计

经过审题,发现可以粗略地设计一下动态规划的状态转移方程。场上使用的是二维的状态转移,即令 \(f(i,j)\) 表示做到前 \(i\) 个,\([i-j+1,i]\) 这段区间相同颜色的方案数,有转移如下:

\[f(i,j)= \begin{cases} \begin{aligned} \max_{len=1}^{i-1} \{f(i,len)+a_i*[a_i=a_{i-len-1}]\} & \space j=1 \\ f(i-1,j-1)+a_i*[a_i=a_{i-1}] & \space j>1 \end{aligned} \end{cases} \]

后面发现无论你怎么优化,时间都会卡在 \(O(n^2)\),这时就应该考虑优化状态设计本身了。

UPD:这个东西如果改一下定义 \(f(i,j)\) 表示前 \(i\) 个,\([j+1,i]\) 这段颜色相同的方案数那么还是挺可做的,但是场上设计的第二维相对数值导致难以直接发现优化。

正确的状态设计

朴素地设计状态,令 \(f(i)\) 表示做了前 \(i\) 个的最大获利。

可以得到:

\[f(i)= \begin{cases} \begin{aligned} &f(i-1)+a_i*[a_i=a_i-1] \\&\max_{j=1}^{i-2}\{f(j+1)+a_i*[a_i=a_j]+g(j+1,i-1)\} \end{aligned} \end{cases} \]

其中 \(g(l,r)\) 表示 \(\begin{aligned}\sum_{i=l+1}^r a_i*[a_i=a_{i-1}] \end{aligned}\)

具体推导过程如下:

首先显然地,\(f(i)\geq f(i-1)+a_i*[a_i=a_i-1]\),因为可以选择不更换颜色,和上一个一样,那么因为 \(a_i>0\)\(f(i)=f(i-1)+a_i*[a_i=a_{i-1}]\) 是至少可以达成的。这样这个状态就有了一个重要性,即单调不减性

再考虑第 \(i\) 个颜色最近与第 \(j(j\le i-2)\) 个一样的情况,这样就有

\[\begin{aligned} f(i)=\max_{j=1}^{i-2}\{f(j+1)+a_i*[a_i=a_j]+g(j+1,i-1)\} \end{aligned} \]

具体来说,中间的 \(g(j+1,i-1)\) 是因为 \(i\)\(j\) 之间是一段连续的颜色,计算它们的贡献的值即为 \(g(j+1,i-1)\)

现在状态是 \(O(n)\),单次转移是 \(O(n)\) 的,到这里其实已经可以写个单调队列之类的东西直接做了,但是还有更好的方法,将单次转移变成 \(O(1)\)

更优的转移

具体地,我们利用单调不减性,发现相邻两个状态如 \(f(j)\)\(f(j-1)\) 至少相差 \(a_j*[a_j=a_{j-1}]\),扩展一下可以得到对于\(j<i\)\(f(i)-f(j)\geq g(j,i)\)

观察第二个转移方程,其实我们发现,\(f(i-1)\) 已经涵盖了前面所有可能颜色段情况的最大值,但是并没有考虑到如果存在 \(a_j=a_i\) 时可以将转移加上 \(a_i\)。我们要做的只是找到前面所有的 \(j\),这样所有的 \(j\) 取值就从 \([1,i-2]\) 变成了 \(\forall j\in[1,i-2],a_i=a_j\)

然而我们还可以进一步优化,我们有结论如下:在第二个转移方程中,\(j\) 取左侧最近一个 \(a_i=a_j\) 的位置一定是最优的。为什么呢?我们做如下分析:

我们不妨称左侧最近一个 \(a_i=a_p\) 的位置为 \(p=pos_{a_i}\),显然这是可以直接处理出来的。

考虑取 \(j<p\)

取到 \(p\) 的贡献:\(f(p+1)+a_i*[a_i=a_p]+g(p+1,i-1)\)

取到 \(j\) 的贡献:\(f(j+1)+a_i*[a_i=a_j]+g(j+1,i-1)\)

两式相减,

由上方推理, \(f(p+1)-f(j+1)\geq g(j+1,p+1)\)

\(p\) 的定义,\(a_i*[a_i=a_p]-a_i*[a_i=a_j]\geq 0\)

\(g\) 的定义,\(g(p+1,i-1)-g(j+1,i-1)=-g(j+1,p)\)

所以最终值为 \(g(j+1,p+1)-g(j+1,p)= a_p*[a_p=a_{p-1}]\geq 0\)

我们证明了取 \(p\) 前面的一定不比 \(p\) 更优。

那么取后面呢?后面的情况有可能比 \(p\) 更优,但是一定不比来自 \(f(i-1)\) 的转移更优,因为来自 \(f(i-1)\) 包含了一切前面任何颜色段的转移,它只是没有考虑如果有 \(a_p=a_i\) 时转移可以加上 \(a_p\) 这一特点而已,这在一开始分析时已经强调过。

至此,我们就完成了优化部分的证明。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5,M=1e6+5;
int t,n,a[N];
LL dp[N],g[N],lst[M];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);lst[a[i]]=0;
			g[i]=g[i-1]+(a[i]==a[i-1])*a[i];
		}
		for(int i=1;i<=n;i++){
			dp[i]=dp[i-1]+(a[i]==a[i-1])*a[i];
			if(lst[a[i]]&&lst[a[i]]<=i-2)
				dp[i]=max(dp[i],dp[lst[a[i]]+1]+g[i-1]-g[lst[a[i]]+1]+a[i]);
			lst[a[i]]=i;
		}
		printf("%lld\n",dp[n]);
	}
	return 0;
}
posted @ 2025-08-11 10:49  TBSF_0207  阅读(46)  评论(4)    收藏  举报