『题解』P9688

题目传送门

思路:

设有两个颜色 \(x_1 x_2\) ,两端分别为 \(l_1\) \(r_1\)\(l_2\) \(r_2\)。通过观察可以发现,若满足 \(x_1<x_2\)\(r_1 > l_2\)\(x_1 x_2\) 一定是单调不下降的。

那么我们可以先预处理出一个颜色可以与前面的哪些颜色构成单调不下降,然后用dp求出最终答案。

\(f_{i\ j}\) 为选择第 \(i\) 个颜色,选择了 \(j\) 个颜色时的最大价值。设可以与 \(i\) 颜色构成单调不下降的颜色为 \(l\)。转移方程为\(f_{i\ j}=max{\ f_{i\ j}\ f_{l\ j-1}}\)

时间复杂度是$ O(N^2K)$

code:

#include <iostream>
#include <vector>
#include <cstring>
#define int long long
using namespace std;
const int Max = 5e2+10;
int n,k;
int a[Max],b[Max];
int l[Max],r[Max];
vector<int>m[Max],c[Max];
int f[Max][Max],ans;
inline int read(){
    int num=0,fl=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') fl=-1;
        c=getchar();
    }
    while(c >='0'&&c <='9'){
        num=(num<<3)+(num<<1)+(c^48);
        c=getchar();
    }
    return num*fl;
}
signed main(){
    memset(f,-0x3f,sizeof f);
    n=read(),k=read();
    for(int i = 1;i <= n;i++){
        a[i]=read();
        m[a[i]].push_back(i);
        if(!l[a[i]])l[a[i]]=i;
        r[a[i]]=i;
    }
    for(int i = 1;i <= n;i++){
        b[i]=read();
    }
    for(int i = 1;i <= n;i++){ //预处理
        if(!m[i].empty()){
            for(int j = 1;j < i;j++){
            	if(!m[j].empty()){
            		if(r[j]<l[i]){
            			c[i].push_back(j);
					}
				}
			}
        }
    }
    f[0][0]=0;//dp初始化
    for(int i = 1;i <= n;i++){
        if(!m[i].empty()){
            f[i][1]=b[i];
        }
    }
    for(int i = 1;i <= n;i++){//dp
        if(!m[i].empty()){
            for(int j = 2;j <= k;j++){
                for(int l=0;l<c[i].size();l++){
                    f[i][j]=max(f[i][j],f[c[i][l]][j-1]+b[i]);
                }
            }    
        }
    }
    for(int i = 1;i <= n;i++){
        ans=max(ans,f[i][k]);
    }
    if(ans==0)printf("-1");
    else printf("%lld",ans);
    return 0;  
}
posted @ 2023-10-04 08:08  tkt  阅读(58)  评论(0编辑  收藏  举报