其他分享
首页 > 其他分享> > permutation

permutation

作者:互联网

套路题
把最大子段和\([l,r]\)变成去掉最小的前/后缀。
把前缀\([1,l-1]\)内的数赋权\(1\),\([l,r]\)的赋权\(2\),\([r+1,n]\)赋权\(3\)、
如果一个数\(x\)是正数,则先把\(ans+=x\),如果\(x\)赋权\(1,3\),\(ans-=x\)
否则如果\(x\)赋权\(2\),\(ans-=x\)。
考虑HNOI2013切糕那样子的建图,把每个点拆成\(i,i'\)两个,建立\(n\)条\(3\)个点的链。
如果\(x\)是正数,则\(s->i,i'->t\)连接\(x\)
否则\(i->i'\)连接\(-x\)。
对于题目的每个限制\((x,y)\),如果\(x\)赋权大于\(y\)赋权则不合法。
用HNOI2013切糕的方法连边限制即可。
\(ans-\)最小割就是答案。

#include<bits/stdc++.h>
using namespace std;
#define M 100010
int h[M],nxt[M],v[M],w[M],s,t,dep[M],ec,m,n,ans;
void add(int a,int b,int c){v[++ec]=b;w[ec]=c;nxt[ec]=h[a];h[a]=ec;}
void adj(int a,int b,int c){
	add(a,b,c);
	add(b,a,0);
}
bool bfs(){
    queue<int>q;
	q.push(s);
    for(int i=1;i<=t;i++)
    	dep[i]=0;
	dep[s]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=nxt[i])
            if(w[i]&&!dep[v[i]]){
            	dep[v[i]]=dep[x]+1;
				q.push(v[i]);
            	if(v[i]==t)
					return 1;
			}
    }
	return 0;
}
int dfs(int x,int dis){
    if(x==t)
		return dis;
	int tp=dis;
    for(int i=h[x];i;i=nxt[i])
        if(dep[v[i]]==dep[x]+1&&w[i]){
            int f=dfs(v[i],min(tp,w[i]));
            if(!f)
				dep[v[i]]=0;
            tp-=f;
            w[i]-=f;
			w[i^1]+=f;
            if(!tp)break;
        }
    return dis-tp;
}
int din(){
    int aans=0;
    while(bfs()){
    	int v;
    	while(v=dfs(s,1e9))
			aans+=v;
	}
    return aans;
}
int main(){
	freopen("permutation.in","r",stdin);
	freopen("permutation.out","w",stdout);
	ec=1;
	scanf("%d%d",&n,&m);
	t=4*n+1;
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		if(x>0){
			ans+=x;
			adj(s,2*i+1,x);
			adj(2*i+2,t,x);
		}
		else
			adj(2*i+1,2*i+2,-x);
	}
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		adj(2*x+1,2*y+1,1e9);
		adj(2*x+2,2*y+2,1e9);
	}
	printf("%d",ans-din());
}

标签:赋权,int,permutation,ec,add,ans,adj
来源: https://www.cnblogs.com/ctmlpfs/p/14956287.html