P9688 Colo. 题解

P9688

由于要求单调,肯定满足对于所有选择的颜色 (x,y) 使得其最左边出现的位置 L 和最右边出现的位置 R,满足 [Lx,Rx][Ly,Ry]=。不然的话肯定不会单调。

直接枚举出现过的颜色,无交的按 L 从小到大连边,且要满足颜色编号从小到大连边,容易发现是一个 DAG,直接在 DAG 上 dp 即可。令 fi,j 表示考虑到 i 区间时,选了 j 个的最大价值,转移显然。边数是 O(n2) 的,单次转移 O(k)

时间复杂度:O(n2k)。实际上远远跑不满。

赛时在连边时没判颜色编号调了很久。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define pb push_back

const int N=510;
const ll inf=1e18;
int n,m,k;
int a[N],b[N],L[N],R[N],deg[N];
ll f[N][N];
vector<int> e[N];
struct node{
    int l,r,id;
    friend bool operator<(node a,node b){
        return a.l<b.l;
    }
};
vector<node> vec;
queue<int> q;

void work(int x,int y){
    if(vec[x].id<vec[y].id&&vec[x].r<vec[y].l)e[x].pb(y),deg[y]++;
}

int main(){
    for(int i=0;i<N;i++)for(int j=1;j<N;j++)f[i][j]=-inf;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(!L[a[i]])L[a[i]]=i;
        R[a[i]]=i;
    }
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++)if(L[i])vec.pb((node){L[i],R[i],i});
    sort(vec.begin(),vec.end());
    m=vec.size();
    for(int i=0;i<m;i++)for(int j=i+1;j<m;j++)work(i,j);
    for(int i=0;i<m;i++)if(!deg[i])q.push(i),f[i][1]=b[vec[i].id];
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int v:e[u]){
            for(int i=1;i<=k;i++)f[v][i]=max(f[v][i],f[u][i-1]+b[vec[v].id]);
            if(!--deg[v])q.push(v);
        }
    }
    ll ans=-inf;
    for(int i=0;i<m;i++)ans=max(ans,f[i][k]);
    cout<<(ans>=k?ans:-1)<<"\n";
    return 0;
}
posted @   Pengzt  阅读(21)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示