1 条题解

  • 0
    @ 2026-5-4 15:38:47

    我们计算以下数组:dp[i][j][k]\text{dp}[i][j][k] 表示涂完前 ii 棵树,使得美感为 jj,且第 ii 棵树被涂成颜色 kk 时所需要的最小油漆用量,并将所有初始值设为 \infty。我们可以通过考虑两种情况来轻松计算这个 DP 数组:

    1. 当上一次使用的颜色与当前颜色相同时,那么如果当前树原本是未涂色的,我们应该用 dp[i1][j][k]+cost[i][k]\text{dp}[i-1][j][k] + \text{cost}[i][k] 来更新;否则直接用 dp[i1][j][k]\text{dp}[i-1][j][k],因为涂色的美感保持不变。

    2. 当上一次使用的颜色与当前颜色不同时,那么我们应该用 dp[i1][j1][l]+cost[i][k]\text{dp}[i-1][j-1][l] + \text{cost}[i][k](如果当前树未涂色)或 dp[i1][j1][l]\text{dp}[i-1][j-1][l](如果当前树已涂色)来更新,其中 1lm1 \le l \le mlkl \neq k。理由类似。

    如果当前树是未涂色的,我们需要遍历所有 mm 种可能的颜色来涂它。

    直接实现这个 DP 的时间复杂度为 O(nkm2)O(n k m^2),对于本题而言已经足够通过。不过,我们可以通过避免在考虑上一次颜色时遍历所有颜色来优化到 O(nkm)O(n k m),即存储两个全局最小值。具体细节请参考代码。

    时间复杂度:O(nkm2)O(n k m^2)O(nkm)O(n k m)

    #include <bits/stdc++.h>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/tree_policy.hpp>
     
    using namespace std;
    using namespace __gnu_pbds;
     
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define fbo find_by_order
    #define ook order_of_key
     
    typedef long long ll;
    typedef pair<int,int> ii;
    typedef vector<int> vi;
    typedef long double ld; 
    typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;
    typedef set<int>::iterator sit;
    typedef map<int,int>::iterator mit;
    typedef vector<int>::iterator vit;
    
    const int N = 101;
    const int MOD = 1e9 + 7;
    const ll INF = ll(1e18);
    
    ll dp[N][N][N];
    int c[N];
    ll cost[N][N];
    ll idx[N][N];
    ll m1[N][N];
    ll m2[N][N];
    
    int main()
    {
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	int n, m, k; cin >> n >> m >> k;
    	for(int i = 1; i <= n; i++)
    	{
    		cin >> c[i];
    	}
    	for(int i = 0; i <= n; i++)
    	{
    		for(int j = 0; j <= k; j++)
    		{
    			m1[i][j] = INF; m2[i][j] = INF; idx[i][j] = -1;
    			for(int a = 0; a <= m; a++)
    			{
    				dp[i][j][a] = INF;
    			}
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			cin >> cost[i][j];
    		}
    	}
    	if(c[1] == 0)
    	{
    		for(int i = 1; i <= m; i++)
    		{
    			dp[1][1][i] = cost[1][i];
    			if(dp[1][1][i] <= m1[1][1])
    			{
    				if(dp[1][1][i] == m1[1][1])
    				{
    					idx[1][1] = -2;
    				}
    				else
    				{
    					idx[1][1] = i;
    				}
    				m2[1][1] = m1[1][1];
    				m1[1][1] = dp[1][1][i];
    			}
    			else if(dp[1][1][i] <= m2[1][1])
    			{
    				m2[1][1] = dp[1][1][i];
    			}
    		}
    	}
    	else
    	{
    		dp[1][1][c[1]] = 0;
    		m1[1][1] = 0; idx[1][1] = c[1];
    	}
    	for(int i = 2; i <= n; i++)
    	{
    		for(int j = 1; j <= k; j++)
    		{
    			if(c[i] == 0)
    			{
    				for(int a = 1; a <= m; a++)
    				{
    					dp[i][j][a] = min(dp[i][j][a], dp[i-1][j][a] + cost[i][a]);
    					ll tmp = INF;
    					if(a == idx[i-1][j-1])
    					{
    						tmp = m2[i-1][j-1];
    					}
    					else
    					{
    						tmp = m1[i-1][j-1];
    					}
    				    dp[i][j][a] = min(dp[i][j][a], tmp + cost[i][a]);
    				}
    			}
    			else
    			{
    				dp[i][j][c[i]] = min(dp[i][j][c[i]], dp[i-1][j][c[i]]);
    				for(int b = 1; b <= m; b++)
    				{
    					if(b != c[i]) dp[i][j][c[i]] = min(dp[i][j][c[i]], dp[i-1][j-1][b]);
    				}
    				//cout << i << ' ' << j << ' ' << c[i] << ' ' << dp[i][j][c[i]] << '\n';
    			}
    			for(int a = 1; a <= m; a++)
    			{
    				if(dp[i][j][a] <= m1[i][j])
    				{
    					if(dp[i][j][a] == m1[i][j])
    					{
    						idx[i][j] = -2;
    					}
    					else
    					{
    						idx[i][j] = a;
    					}
    					m2[i][j] = m1[i][j];
    					m1[i][j] = dp[i][j][a];
    				}
    				else if(dp[i][j][a] <= m2[i][j])
    				{
    					m2[i][j] = dp[i][j][a];
    				}
    			}
    		}
    	}
    	ll ans = INF;
    	for(int i = 1; i <= m; i++)
    	{
    		ans = min(ans, dp[n][k][i]);
    	}
    	if(ans >= INF) ans = -1;
    	cout << ans;
    }
    
    • 1

    信息

    ID
    6808
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    1
    已通过
    1
    上传者