1 条题解
-
0
自动搬运
来自洛谷,原作者为

lhm_
sjzez 的一名 OI 学生搬运于
2025-08-24 22:09:38,当前版本为作者最后更新于2020-05-27 00:18:13,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
考虑用费用流解决本题。
每个哨站看作一个点,并将其拆为两个点,建图方式为:
容量为,费用为
容量为,费用为
容量为,费用为
容量为,费用为
这样就可以满足题目要求了,跑最小费用最大流即可求解,但发现边数为级别,所以要考虑优化建图。
一个点在和拆出来的点连边时,只会向下标比其小的点连边,所以可以通过分治来实现优化建图。
对于区间,分成两个区间和,每次从右区间向左区间连边。还需考虑费用的绝对值如何处理,可以把这一区间内所有的权值排序去重,然后连成一条链,链上边的费用为相邻两点的权值之差,然后把这条链作为连接右区间和左区间的虚点。
区间内的点向虚点连边时,只需找到其权值所对应到链上的位置,然后向对应位置连边即可,这样就通过累积权值之间的差值实现了费用的绝对值。
#include<bits/stdc++.h> #define maxn 800010 #define inf 2000000000 using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,w,tot,cnt,s,t; int p1[maxn],p2[maxn]; ll a[maxn],b[maxn],dis[maxn]; bool vis[maxn]; struct edge { int to,nxt,v; ll c; }e[maxn]; int head[maxn],edge_cnt=1; void add(int from,int to,int val,ll cost) { e[++edge_cnt]=(edge){to,head[from],val,cost}; head[from]=edge_cnt; e[++edge_cnt]=(edge){from,head[to],0,-cost}; head[to]=edge_cnt; } bool spfa() { for(int i=1;i<=tot;++i) vis[i]=0,dis[i]=inf; queue<int> q; q.push(s),dis[s]=0,vis[s]=true; while(!q.empty()) { int x=q.front(); q.pop(),vis[x]=false; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to,v=e[i].v; ll c=e[i].c; if(v&&dis[y]>dis[x]+c) { dis[y]=dis[x]+c; if(!vis[y]) q.push(y),vis[y]=true; } } } return dis[t]!=inf; } int dfs(int x,int lim) { if(x==t) return lim; vis[x]=true; int res=lim,flow; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to,v=e[i].v; ll c=e[i].c; if(!v||dis[y]!=dis[x]+c||vis[y]) continue; if(flow=dfs(y,min(res,v))) { res-=flow; e[i].v-=flow; e[i^1].v+=flow; if(!res) break; } } return lim-res; } ll dinic() { int flow; ll sum=0; while(spfa()) while(flow=dfs(s,inf)) sum+=flow*dis[t]; return sum; } void solve(int l,int r) { if(l==r) return; int mid=(l+r)>>1; solve(l,mid),solve(mid+1,r),cnt=0; for(int i=l;i<=r;++i) b[++cnt]=a[i]; sort(b+1,b+cnt+1),cnt=unique(b+1,b+cnt+1)-b-1; for(int i=1;i<cnt;++i) { add(tot+i,tot+i+1,inf,b[i+1]-b[i]); add(tot+i+1,tot+i,inf,b[i+1]-b[i]); } for(int i=l;i<=r;++i) { int pos=lower_bound(b+1,b+cnt+1,a[i])-b; if(i>mid) add(p1[i],tot+pos,1,0); else add(tot+pos,p2[i],1,0); } tot+=cnt; } int main() { read(n),read(w),s=++tot,t=++tot; for(int i=1;i<=n;++i) read(a[i]); for(int i=1;i<=n;++i) { p1[i]=++tot,p2[i]=++tot; add(s,p1[i],1,0),add(p1[i],t,1,w),add(p2[i],t,1,0); } solve(1,n),printf("%lld",dinic()); return 0; }
- 1
信息
- ID
- 4320
- 时间
- 5000ms
- 内存
- 500MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者