P9688 Colo. 题解
由于要求单调,肯定满足对于所有选择的颜色 $(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;
}