Lis(bzoj 3532)
Description
给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。
如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
Input
输入包含多组数据。
输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。
Output
对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在4中的的位置,按升序输出。
Sample Input
1
6
3 4 4 2 2 3
2 1 1 1 1 2
6 5 4 3 2 1
6
3 4 4 2 2 3
2 1 1 1 1 2
6 5 4 3 2 1
Sample Output
4 3
2 3 6
解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但
{A2,43,A6)对应的C值的字典序最小。
2 3 6
解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但
{A2,43,A6)对应的C值的字典序最小。
HINT
1 < =N < =700 T < =5
/* 如果没有字典序最小的要求,建图跑最小割。 建图方法: S向i连一条容量为inf的边; i'向T连一条容量为inf的边; i向i'连一条容量为b[i]的边; 如果a[i]<a[j]&&f[i]+1=f[j],i'向j连一条容量为inf的边。 现在有字典序最小的要求,那么有字典序从小到大枚举删哪条边,删一条边<u,v>的方法是: 退流,u向S跑一遍最大流,,T向v跑一遍最大流,然后这条边流量清零就行了。 */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define N 710 #define inf 1000000000 using namespace std; int a[N],b[N],f[N],head[N],dis[N],n,cnt,ans[N]; struct Node{int num,id;}c[N]; struct node{int v,f,pre;}e[N*N]; queue<int> q; bool cmp(const Node&x,const Node&y){return x.num<y.num;} void add(int u,int v,int f){ e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt; e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt; } bool bfs(int S,int T){ memset(dis,-1,sizeof(dis)); q.push(S);dis[S]=0; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].pre) if(e[i].f&&dis[e[i].v]==-1){ dis[e[i].v]=dis[u]+1; q.push(e[i].v); } } return dis[T]!=-1; } int dfs(int x,int f,int T){ if(x==T||f==0) return f; int rest=f; for(int i=head[x];i;i=e[i].pre) if(e[i].f&&dis[e[i].v]==dis[x]+1){ int v=dfs(e[i].v,min(rest,e[i].f),T); if(!v) dis[e[i].v]=-1; e[i].f-=v; e[i^1].f+=v; rest-=v; } if(f==rest) dis[x]=0; return f-rest; } int dinic(int S,int T){ int ans=0; while(bfs(S,T)) ans+=dfs(S,inf,T); return ans; } int DP(){ int maxf=0; for(int i=1;i<=n;i++){ int maxn=0; for(int j=0;j<i;j++) if(a[j]<a[i]) maxn=max(maxn,f[j]); f[i]=maxn+1; maxf=max(maxf,f[i]); } return maxf; } void build(int S,int T){ int maxf=DP(); for(int i=1;i<=n;i++) add(i,i+n,b[i]); for(int i=1;i<=n;i++){ if(f[i]==1) add(S,i,inf); else if(f[i]==maxf) add(i+n,T,inf); for(int j=i+1;j<=n;j++) if(a[i]<a[j]&&f[i]+1==f[j]) add(i+n,j,inf); } } int main(){ int Q;scanf("%d",&Q); while(Q--){ memset(head,0,sizeof(head)); cnt=1; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) scanf("%d",&c[i].num),c[i].id=i; int S=0,T=n*2+1; build(S,T); int maxflow=dinic(S,T); sort(c+1,c+n+1,cmp); int tot=0; for(int i=1;i<=n;i++){ int u=c[i].id,v=u+n; if(bfs(u,v)) continue; ans[++tot]=u; dinic(u,S);dinic(T,v); e[u*2].f=e[u*2+1].f=0; } sort(ans+1,ans+tot+1); printf("%d %d\n",maxflow,tot); for(int i=1;i<=tot;i++) printf("%d%c",ans[i],i==tot?'\n':' '); } return 0; }