zoukankan      html  css  js  c++  java
  • Topcoder 14719

    题面传送门

    神仙最小割……好久没写过网络流了,故写题解以祭之(

    首先考虑一个非常 trivial 的问题:如果知道排列顺序之后怎样计算最大值,用脚趾头想一下就能知道是原序列的最大子段和,因为每个课程之后的 rating 显然相当于前缀和,前缀和相减自然就是区间和了。

    我们假设最大区间和为 ([l,r]),那么我们考虑将序列分成三段 ([1,l-1],[l,r],[r+1,n]),一个很显然的性质是由于限制关系不成环,因此段内部的相对位置关系是不重要的,也就是说我们只要钦定每个元素在哪一段,就总存在一种排列方式符合限制要求。而显然一个元素只有在中间一段才能对答案产生贡献。

    这样就可以最小割了呗,记 (S=sumlimits_{i=1}^nmax(w_i,0)),也就是 (w) 序列中所有正权值的和,我们考虑这样建图:将每个点拆成 (in_i)(out_i) 两个点,对于 (w_i>0) 的点连边 (S o in_i),容量 (w_i)(in_i o out_i),容量 (0)(out_i o T),容量 (w_i);对于 (w_i<0) 的点连边 (S o in_i),容量 (0)(in_i o out_i),容量 (-w_i)(out_i o T),容量 (0)。割掉 (S o in_i) 的边表示 (i) 在第一段 ([1,l-1]),割掉 (in_i o out_i) 表示 (i) 在第二段 ([l,r]),割掉 (out_i o T) 表示 (i) 在第三段 ([r+1,n])。那么怎么处理限制关系呢?对于每对 (a_i,b_i) 连边 (in_{a_i} o in_{b_i},out_{a_i} o out_{b_i}),容量均为 (infty) 即可。然后答案就是 (S-) 最小割。

    const int MAXV=102;
    const int MAXE=2.5e3*2;
    const int INF=0x3f3f3f3f;
    int n,S,T,hd[MAXV+5],to[MAXE+5],nxt[MAXE+5],cap[MAXE+5],ec=1;
    void adde(int u,int v,int f){
    	to[++ec]=v;cap[ec]=f;nxt[ec]=hd[u];hd[u]=ec;
    	to[++ec]=u;cap[ec]=0;nxt[ec]=hd[v];hd[v]=ec;
    }
    int dep[MAXV+5],now[MAXV+5];
    bool getdep(){
    	memset(dep,-1,sizeof(dep));dep[S]=0;
    	queue<int> q;q.push(S);now[S]=hd[S];
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int e=hd[x];e;e=nxt[e]){
    			int y=to[e],z=cap[e];
    			if(z&&!~dep[y]){
    				dep[y]=dep[x]+1;
    				now[y]=hd[y];q.push(y);
    			}
    		}
    	} return ~dep[T];
    }
    int getflow(int x,int f){
    	if(x==T) return f;int ret=0;
    	for(int &e=now[x];e;e=nxt[e]){
    		int y=to[e],z=cap[e];
    		if(z&&dep[y]==dep[x]+1){
    			int w=getflow(y,min(f-ret,z));
    			ret+=w;cap[e]-=w;cap[e^1]+=w;
    			if(f==ret) return ret;
    		}
    	} return ret;
    }
    int dinic(){
    	int ret=0;
    	while(getdep()) ret+=getflow(S,INF);
    	return ret;
    }
    struct RatingProgressAward{
    	int maximalProgress(vector<int> val,vector<int> a,vector<int> b){
    		n=val.size();T=(S=n<<1|1)+1;int sum=0;
    		for(int i=1;i<=n;i++){
    			if(val[i-1]>0) adde(S,i,val[i-1]),adde(i,i+n,0),adde(i+n,T,val[i-1]),sum+=val[i-1];
    			else adde(S,i,0),adde(i,i+n,-val[i-1]),adde(i+n,T,0);
    		} for(int i=0;i<a.size();i++){++a[i];++b[i];adde(a[i],b[i],INF);adde(a[i]+n,b[i]+n,INF);}
    		return sum-dinic();
    	}
    };
    
  • 相关阅读:
    ssh_jar包选择
    去js校验
    CSS
    html(HyperText Markup Language)--超文本标记语言
    Java compiler level does not match解决方法
    linux上面是否有安装redis,redis启动
    mybatis 详解(九)------ 一级缓存、二级缓存
    mybatis 详解(八)------ 懒加载
    mybatis 详解(六)------通过mapper接口加载映射文件
    mybatis 详解(七)------一对一、一对多、多对多
  • 原文地址:https://www.cnblogs.com/ET2006/p/topcoder-14719.html
Copyright © 2011-2022 走看看