P9688 Colo. 题解

P9688

由于要求单调,肯定满足对于所有选择的颜色 $(x,y)$ 使得其最左边出现的位置 $L$ 和最右边出现的位置 $R$,满足 $[L_x,R_x]\bigcap[L_y,R_y]=\varnothing$。不然的话肯定不会单调。

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

时间复杂度:$\mathcal{O}(n^2k)$。实际上远远跑不满。

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

代码:

#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 @ 2023-10-02 22:55  Pengzt  阅读(16)  评论(0编辑  收藏  举报  来源