【BZOJ-3532】Lis 最小割 + 退流

3532: [Sdoi2014]Lis

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 704  Solved: 264
[Submit][Status][Discuss]

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

Sample Output

4 3
2 3 6
解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但{A2,43,A6)对应的C值的字典序最小。

HINT

1 < =N < =700     T < =5

Source

Round 1 Day 2

Solution

最小割的模型还是很显然的,先dp一边,然后转移之间连边,源点到初始状态,最终状态到汇点,拆点限制流量,最小割即删去的代价。

然后考虑字典序最小的割,可以通过按字典序枚举每条限流边,如果这条边满流且无法再流过去,则这条割边可选,然后消除它的影响,继续处理。

消除影响可以利用退流的思想,其实就是将这条边<u,v>正反置0,然后跑一遍T->v,一遍u->S即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

inline int read()
{
	int x=0,f=1; char ch=getchar();
	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

#define MAXN 5010
int N,cas,a[MAXN],b[MAXN],c[MAXN];

struct EdgeNode{
	int next,to,cap;
}edge[2000100];
int head[MAXN],cnt=1;
inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,0);}

int h[MAXN],cur[MAXN],S,T;
queue<int>q;
inline bool bfs(int s,int t)
{
	for (int i=S; i<=T; i++) h[i]=-1;
	q.push(s); h[s]=0;
	while (!q.empty()) {
		int now=q.front(); q.pop();
		for (int i=head[now]; i; i=edge[i].next) 
			if (edge[i].cap && h[edge[i].to]==-1)
				h[edge[i].to]=h[now]+1,q.push(edge[i].to);
	}
	return h[t]!=-1;
}

inline int dfs(int now,int low,int s,int t)
{
	if (now==t) return low;
	int w,used=0;
	for (int i=cur[now]; i; i=edge[i].next) 
		if (edge[i].cap && h[edge[i].to]==h[now]+1) {
			int w=dfs(edge[i].to,min(low-used,edge[i].cap),s,t);
			edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
			if (used==low) return used;
			if (edge[i].cap) cur[now]=i;
		}
	if (!used) h[now]=-1;
	return used;
}

#define INF 0x7fffffff
inline int Dinic(int s,int t)
{
	int re=0;
	while (bfs(s,t)) {
		for (int i=S; i<=T; i++) cur[i]=head[i];
		re+=dfs(s,INF,s,t);
	}
	return re;
}

#define Pa pair<int,int>
#define MP make_pair
#define Id first
#define ps second

inline bool cmp(Pa x,Pa y) {return c[x.Id]<c[y.Id];}

int stack[MAXN],top=0;
int main()
{
	cas=read();
	while (cas--) {
		cnt=1;
		memset(head,0,sizeof(head));
		
		N=read();
		for (int i=1; i<=N; i++) a[i]=read();
		for (int i=1; i<=N; i++) b[i]=read();
		for (int i=1; i<=N; i++) c[i]=read();
		
		static int f[MAXN];
		
		for (int i=1; i<=N; i++) f[i]=1;
		
		for (int i=1; i<=N; i++)
			for (int j=0; j<i; j++)
				if (a[i]>a[j]) f[i]=max(f[i],f[j]+1);
		
		int mx=0;
		for (int i=1; i<=N; i++) mx=max(mx,f[i]);
		
		S=0,T=2*N+1;
		
		static Pa id[MAXN];
		
		for (int i=1; i<=N; i++) {
			if (f[i]==1) InsertEdge(S,i,INF);
			if (f[i]==mx) InsertEdge(i+N,T,INF);
			InsertEdge(i,i+N,b[i]); id[i]=MP(i,cnt);
			for (int j=1; j<i; j++)
				if (f[i]-1==f[j] && a[i]>a[j]) InsertEdge(j+N,i,INF);
		}
		
		int ans=Dinic(S,T);
		
		stable_sort(id+1,id+N+1,cmp);
		
		top=0;
		for (int i=1; i<=N; i++) {
			int e1=id[i].ps^1,e2=id[i].ps,p1=id[i].Id,p2=p1+N;
			if (!edge[e1].cap && !bfs(p1,p2)) {
				Dinic(p1,S); Dinic(T,p2);
				edge[e1].cap=edge[e2].cap=0;
				stack[++top]=id[i].Id;
			}
		}
		
		stable_sort(stack+1,stack+top+1);

		printf("%d %d\n",ans,top);
		for (int i=1; i<top; i++) printf("%d ",stack[i]); printf("%d\n",stack[top]);
		
	}
	return 0;
}

  

posted @ 2017-03-13 07:05  DaD3zZ  阅读(328)  评论(0编辑  收藏