• bzoj 3532: [Sdoi2014]Lis


    Description

    给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
    干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。
    如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。

    Solution

    首先可以建图求出最小的代价和 .
    由于是删除点 , 所以我们可以要拆点 .
    于是分成两个集合 (i,i+n) .
    如果 (f[i]=1) , (S->i)
    如果 (f[i]=maxf) (i+n->T)
    如果 (f[i]=f[j]+1&&a[j]<a[i]) , (i+n->i)
    最小割就是答案 .
    然后考虑构造字典序最小的解 , 首先按 (C_i) 排序 , 从小到大考虑 .
    一条边能够加入最小割显然要加入 , 我们就需要判断这条边是否存在最小割集中就行了 .
    一种方法是减小 (i->i+n) 这条边 (1) 的流量 , 如果最小割也减少 (1) 那么就可以成为最小割的一条边
    也可以通过判断是否存在 (i->i+n) 的增广路 , 如果存在则不会在最小割集中 .
    这样的话我们删除一条边 ((u,v,c)) 后要消除它的影响 , 为了节省复杂度 .
    (maxflow(T,v,c),maxflow(u,S,c)) 再把这条边容量清零 , 最后再跑一边 (maxflow(S,T,inf)) 就好了.
    但是这个题的图有特殊性质 , 所以只需要 (maxflow(T,v),maxflow(u,S)) 就好了.
    注意常数优化 :
    比如 (bfs) 的时候要在遍历到 (T) 时就 $return $ .

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=1550,inf=2e9;
    int n,c[N],id[N],a[N],b[N],f[N];
    int dis[N*N],S=0,T,head[N],nxt[N*N],to[N*N],num=1,dep[N],ans[N];
    inline void link(int x,int y,int z){
    	nxt[++num]=head[x];to[num]=y;head[x]=num;dis[num]=z;
    	nxt[++num]=head[y];to[num]=x;head[y]=num;dis[num]=0;
    }
    inline bool comp(const int &i,const int &j){return c[i]<c[j];}
    inline bool bfs(int s,int t){
    	queue<int>Q;
    	for(int i=2*n+1;i>=0;i--)dep[i]=0;
    	Q.push(s);dep[s]=1;
    	while(!Q.empty()){
    		int x=Q.front();Q.pop();
    		for(int i=head[x];i;i=nxt[i]){
    			if(dis[i]<=0 || dep[to[i]])continue;
    			int u=to[i];
    			dep[u]=dep[x]+1;Q.push(u);
    			if(u==t)return 1;
    		}
    	}
    	return dep[t];
    }
    inline int dfs(int x,int flow){
    	if(x==T || !flow)return flow;
    	int tot=0,t;
    	for(int i=head[x];i;i=nxt[i]){
    		int u=to[i];
    		if(dis[i]<=0 || dep[u]!=dep[x]+1)continue;
    		t=dfs(u,min(flow,dis[i]));
    		dis[i]-=t;dis[i^1]+=t;tot+=t;flow-=t;
    		if(!flow)break;
    	}
    	if(!tot)dep[x]=-1;
    	return tot;
    }
    inline int Dinic(int s,int t){
    	S=s;T=t;
    	int tot=0,x;
    	while(bfs(s,t)){
    		x=dfs(s,inf);
    		while(x)tot+=x,x=dfs(s,inf);
    	}
    	return tot;
    }
    inline void work(){
    	int cnt=0;
    	memset(head,0,sizeof(head));num=1;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)gi(a[i]);
    	for(int i=1;i<=n;i++)gi(b[i]);
    	for(int i=1;i<=n;i++)gi(c[i]),id[i]=i;
    	sort(id+1,id+n+1,comp);
    	int maxf=1;
    	for(int i=1;i<=n;i++){
    		f[i]=1;
    		for(int j=1;j<i;j++)if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
    		maxf=max(maxf,f[i]);
    	}
    	for(int i=1;i<=n;i++){
    		if(f[i]==1)link(0,i,inf);
    	   if(f[i]==maxf)link(i+n,2*n+1,inf);
    		for(int j=1;j<i;j++)
    			if(f[j]+1==f[i] && a[j]<a[i])link(j+n,i,inf);
    		link(i,i+n,b[i]);
    	}
    	int sum=Dinic(0,2*n+1);
    	for(int i=1;i<=n;i++){
    		int u=id[i],v=id[i]+n;
    		if(bfs(u,v))continue;
    		Dinic(2*n+1,v);Dinic(u,0);
    		ans[++cnt]=u;
    	}
    	sort(ans+1,ans+cnt+1);
    	printf("%d %d
    ",sum,cnt);
    	printf("%d",ans[1]);
    	for(int i=2;i<=cnt;i++)printf(" %d",ans[i]);
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      int T;cin>>T;
      while(T--)work(),T?puts(""):0;
      return 0;
    }
    
    
  • 相关阅读:
    TinyOS功率编程指南
    深度学习入门资料
    通信常识
    CTF入门
    前端开发工具之服务器选择
    Spring
    NoSQL -- MongoDB
    NoSQL -- Redis
    mysql alter table修改表结构添加多个字段的几个写法
    gongle 访问助手安装
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9248493.html
Copyright © 2020-2023  润新知