题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3532
题意:给出三个数列ABC,长度均为n。删除A中的某些数字,使得A的最长上升子列至少减少1。删掉的数字的代价为相应的B值之和。要求使得代价最小。多组答案时,使得删掉的数字的C值排序的字典序最小。
思路:假设不考虑字典序。那么只要拆点求最小割即可。设f[i]表示到i的最长上升子列。对于两个数字(i,j),若A[i]<A[j]且f[i]+1=f[j],则i向j连边。对于每个点拆开的点连边为B值。
现在要求字典序最小,首先按照C排序,然后从小到大枚举。对于数字x判断其是否在最小割中。若其代表的边(x1,x2)之间的流量为0,且在残留网络中x1不能到达x2,那么x在最小割中。之后还要去掉x这条边。只需要将这条边以及反向边的流量设为0,同时跑(T,x2)(x1,S)的最大流即可,这样可以恢复x原来的边带来的影响。
const int INF=2000000005;const int N=1444; struct node{ int v,next; int cap;}; node edges[1100000];int head[N],e;int curedge[N]; inline void add(int u,int v,int cap){ edges[e].v=v; edges[e].cap=cap; edges[e].next=head[u]; head[u]=e++;} inline void Add(int u,int v,i64 cap){ add(u,v,cap); add(v,u,0);} int S,T; int dis[N]; int Q[N]; int bfs(int s,int t){ clr(dis,-1); int i; for(i=S;i<=T;i++) curedge[i]=head[i]; int L=0,R=0; dis[t]=0; Q[R++]=t; while(LC[777];int A[777],B[777];int n; int f[777]; int num[777]; int main(){ int cse=getInt(); while(cse--) { n=getInt(); int i; for(i=1;i<=n;i++) A[i]=getInt(); for(i=1;i<=n;i++) B[i]=getInt(); for(i=1;i<=n;i++) C[i].first=getInt(),C[i].second=i; int j; int Max=1; for(i=1;i<=n;i++) { f[i]=1; for(j=1;j 1) putchar(' '); printf("%d",a[i]); } puts(""); }}