CF711C Coloring Trees

fi,j,kf_{i,j,k} 表示前 ii 个点,第 ii 个点染为 jj,分成 kk 段的最小花费。

转移方程:

  • ii 个点已被染色:fi,coli,k=min(fi,coli,k,fi1,lst,k[lstcoli])f_{i,col_i,k}=\min(f_{i,col_i,k},f_{i-1,lst,k-[lst \ne col_i]})
  • ii 个点未被染色:fi,j,k=min(fi,j,k,fi1,lst,k[lstj]+costi,j)f_{i,j,k}=\min(f_{i,j,k},f_{i-1,lst,k-[lst\ne j]}+cost_{i,j})

时间复杂度 O(nkm2)\mathcal O(nkm^2),可用 st 表优化到 O(nkmlogm)\mathcal O(nkm\log m)

#include <bits/stdc++.h>

using namespace std;

#define int long long

inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		x = x * 10 + c - '0', c = getchar();
	return x * f;
}

#define inf 0x7f7f7f7f7f7f

const int _ = 208;

int n, m, k, ans = inf, col[_], cost[_][_], dp[_][_][_];

signed main()
{
	n = read(), m = read(), k = read();
	for(int i = 1; i <= n; ++i) col[i] = read();
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j) cost[i][j] = read();
	memset(dp, inf, sizeof dp);
	if(col[1]) dp[1][col[1]][1] = 0;
	else for(int i = 1; i <= m; ++i) dp[1][i][1] = cost[1][i];
	for(int i = 2; i <= n; ++i)
		for(int j = 1; j <= k && j <= i; ++j)
			if(col[i])
			{
				for(int l = 1; l <= m; ++l)
					dp[i][col[i]][j] = min(dp[i][col[i]][j], dp[i - 1][l][j - (col[i] == l ? 0 : 1)]);
			}
			else
			{
				for(int l = 1; l <= m; ++l)
					for(int p = 1; p <= m; ++p)
						dp[i][l][j] = min(dp[i][l][j], dp[i - 1][p][j - (l == p ? 0 : 1)] + cost[i][l]);
			}
	if(col[n]) ans = dp[n][col[n]][k];
	else for(int i = 1; i <= m; ++i) ans = min(ans, dp[n][i][k]);
	printf("%lld", (ans < inf) ? ans : -1);
	return 0;
}
posted @ 2022-12-01 08:44  蒟蒻orz  阅读(13)  评论(0)    收藏  举报  来源