Topcoder 14719 - RatingProgressAward(最小割)
阅读原文时间:2023年07月09日阅读:2

题面传送门

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

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

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

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器