P9688 Colo. 题解

题目传送门~

题目分析

我们发现“从左到右颜色的编号是单调不下降的”,可以联想到经典 DP 问题:最长单调不下降子序列。因此这一题可以参考最长不降序列的写法。

注:本人思路并非最好,但个人认为较好理解。

设计状态转移方程:dpn,m 表示前 n 个选择 k 种颜色获得的最大价值。 由最长不降序列的 DP 写法,可以类比得到:dpi,k=max(dpj,k1+v)

推出转移式子后,只剩下判断每个 j 是否可以转移。

这里除了要判断 ij 单调不降,还需要判断 j 的颜色的最后出现的下标是否大于 i 的颜色的最前出现的下标,若大于,即出现了上升的情况,矛盾。

具体见代码实现。

#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
#define INF 0x3f3f3f3f
#define re register
#define il inline
#define gc getchar
#define int ll //记得开long long!

const int N = 505;
int n,k,a[N],b[N],dp[N][N],from[N],bk[N],pre[N];

signed main()
{

    memset(bk,-1,sizeof bk);
    memset(pre,-1,sizeof pre);
    cin >> n >> k;
    for (int i = 1;i <= n;i++) scanf("%lld",&a[i]);
    for (int j = 1;j <= n;j++) scanf("%lld",&b[j]);
    for (int i = 1;i <= n;i++) dp[i][1] = b[a[i]];
    //预处理出每个颜色最前和最后所在位置
    for (int i = 1;i <= n;i++)
        if (pre[a[i]] == -1) pre[a[i]] = i;
    for (int i =n;i >= 1;i--)
        if (bk[a[i]] == -1) bk[a[i]] = i;

    for (int e = 1;e <= k;e++) //枚举保留k个
        for (int i = 1;i <= n;i++) //枚举以第i个结尾
            for (int j = 1;j < i;j++) // 用第j个转移
                if (a[j] < a[i] && bk[a[j]] < pre[a[i]] && dp[j][e-1])
                {
                    //状态转移
                    dp[i][e] = max(dp[i][e],dp[j][e-1]+b[a[i]]);
                }

    int res = 0;
    for (int i = 1;i <= n;i++) res = max(res,dp[i][k]);
    if (!res) puts("-1");
    else cout << res << endl;
    return 0;
}
posted @   codwarm  阅读(36)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示