首页 > 其他分享 >P7730 [JDWOI-1] 蜀道难

P7730 [JDWOI-1] 蜀道难

时间:2024-09-30 15:12:16浏览次数:6  
标签:JDWOI head 蜀道难 int P7730 tot vis cost dis

首先,区间增加定值并且要求单调不降,很容易想到差分。

于是先把 \(h\) 数组差分一下,题目的要求即为最小代价使得 \(h\) 均为非负数。

观察一下两种操作,发现 \(n\) 的范围很小,可以枚举操作的起点 \(i\) ,然后如果操作是压低,相当于 \(h[i]--,h[i+l[i]]++\) 。
image

而如果操作是抬高,相当于 \(h[i]++,h[i+l[i]]--\) 。

显然差分数组的总和是一定的(边界有点小问题下文会提及),那么可以把压低当成一条 \(i\) 到 \(i+l[i]\) 的流,抬高也是同理。

注意当 \(i+l[i]-1\) 恰好为 \(n\) 时 \(i+l[i]\) 为 \(n+1\) 但是这个操作显然是合法的,所以要增加一个 \(n+1\) 号点, \(h[n+1]\) 设为 \(h\) 的上限。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200010;
const int INF=1000000000;
int increase[N],to[N],head[N];
int flow[N],cost[N],nxt[N];
int pre[N];
int maxflow,tot;
bool vis[N];
int dis[N];
int n,m,s,t,ans,a,b;
int h[N];
 
void add(int x,int y,int z,int c){
	to[++tot]=y;
	flow[tot]=z;
	cost[tot]=c;
	nxt[tot]=head[x];
	head[x]=tot;
	to[++tot]=x;
	flow[tot]=0;
	cost[tot]=-c;
	nxt[tot]=head[y];
	head[y]=tot;
}

bool spfa(){
	memset(increase,0x3f,sizeof(increase));
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	int kep=dis[t];
	dis[s]=0;
	queue<int> q;
	q.push(s);
	vis[s]=true;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vis[x]=false;
		for(int i=head[x];i;i=nxt[i]){
			int y=to[i];
			if(flow[i] && dis[y]>dis[x]+cost[i]){
				dis[y]=dis[x]+cost[i];
				increase[y]=min(increase[x],flow[i]);
				pre[y]=i;
				if(!vis[y]){
					vis[y]=true;
					q.push(y);
				}
			}
		}
	}
	return dis[t]<kep;
}

void update(){
	int cur=t;
	while(cur!=s){
		int last=pre[cur];
		flow[last]-=increase[t];
		flow[last^1]+=increase[t];
		cur=to[last^1];
	}
	maxflow+=increase[t];
	ans+=(increase[t]*dis[t]);
}

inline int read(){
    char ch;int x=0;bool f=false;
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=true;
    for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    if(f) x=-x;
    return x;
}

signed main(){
	cin>>n>>m;
	s=0,t=n+2;
	h[n+1]=10000;
	tot=1;
	for(int i=1;i<=n;i++){
	    h[i]=read();
    }
    for(int i=n;i>=1;i--){
        h[i]-=h[i-1];
    }
    char c;
    for(int i=1;i<=m;i++){
        cin>>c;
        a=read(),b=read();
        for(int j=1;j<=n-a+1;j++){
            int k=j+a;
            if(c=='-') add(j,k,INF,b);
            else add(k,j,INF,b);
        }
    }
    for(int i=1;i<=n+1;i++){
        //cout<<"h[i]: "<<i<<" "<<h[i]<<"\n";
        add(s,i,h[i]+1001,0),add(i,t,1001,0);
    }
	while(spfa()){
		update();
	}
	if(maxflow!=1001*(n+1)) cout<<-1;
	else cout<<ans;
	return 0;
}

标签:JDWOI,head,蜀道难,int,P7730,tot,vis,cost,dis
From: https://www.cnblogs.com/wangwenhan/p/18441886

相关文章

  • P7730 [JDWOI-1] 蜀道难
    感觉每一步都挺自然的。首先连续加减让我们不难想到差分,每次给\(d_i\)加一或减一,每次给\(d_{i+l}\)减一或加一。然后要求单调不降就是要求每个\(d_i\)大于等于\(0\)。然后注意到我们每次操作相当于是\(i\)向\(i+l\)贡献\(1\)或者\(i+l\)向\(i\)贡献\(1\),结合......