题解:
比较简单的建图法就是看做小于
k
k
k条流在一个
n
∗
n
n*n
n∗n序列上流,其中一些位置是必须流的,然后做个上下界费用流。
不过注意到肯定有一种方案使得这小于 k k k条流是不相交的,于是可以直接看做有 n n n个点,每个点拆点连 − ∞ -\infty −∞的边,然后规定这个点必须是 a i a_i ai,然后跑个最小费用可行流,这样 n n n个 − ∞ -\infty −∞必定流满,此外其他加起来最小。
最后加个 n ∗ ∞ n * \infty n∗∞即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e4+50;
const LL inf=1e14;
namespace mcmf {
int src,des,ec=1,tl;
int cur[N],g[N],nt[N],vt[N],c[N],walk[N],exi[N],q[N];
LL w[N],dis[N],ans;
inline void add(int x,int y,int cc,LL ww) {
nt[++ec]=g[x]; g[x]=ec; vt[ec]=y; c[ec]=cc; w[ec]=ww;
nt[++ec]=g[y]; g[y]=ec; vt[ec]=x; c[ec]=0; w[ec]=-ww;
}
inline bool spfa() {
for(int i=1;i<=des;i++) cur[i]=g[i], dis[i]=inf*100, walk[i]=0;
q[tl=1]=src; dis[src]=0;
for(int i=1;i<=tl;i++) {
int u=q[i]; exi[u]=0;
for(int e=g[u];e;e=nt[e])
if(c[e] && dis[vt[e]]>dis[u]+w[e]) {
dis[vt[e]]=dis[u]+w[e];
if(!exi[vt[e]]) exi[vt[e]]=1, q[++tl]=vt[e];
}
} return dis[des]!=inf*100;
}
inline int dinic(int x,int f,LL cost) {
if(x==des) {ans+=f*cost; return f;}
int rs=0; walk[x]=1;
for(int &e=cur[x];e;e=nt[e]) {
if(c[e] && (dis[vt[e]]==dis[x]+w[e]) && !walk[vt[e]]) {
int o=dinic(vt[e],min(f-rs,c[e]),cost+w[e]);
c[e]-=o; c[e^1]+=o; rs+=o;
if(rs==f) return rs;
}
} return dis[x]=inf*100,rs;
}
int lim;
inline LL mcmf() {
while(lim && spfa() && dis[des]<0)
lim-=dinic(src,lim,0);
return ans;
}
} using mcmf::add;
int n,a[N],c[N];
int main() {
cin>>n>>mcmf::lim;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>c[i];
mcmf::src=2*n+1; mcmf::des=2*n+2;
for(int i=1;i<=n;i++)
add(mcmf::src,i,1,c[a[i]]), add(i+n,mcmf::des,1,0), add(i,i+n,1,-inf);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(a[i]==a[j]) add(i+n,j,1,0);
else add(i+n,j,1,c[a[j]]);
cout<<mcmf::mcmf()+n*inf<<'\n';
}