Gym 101190D BZOJ 4842 Luogu P6967 LOJ #6071 [NEERC2016]Delight for a Cat (费用流)
題目鏈接
(BZOJ) 大人,時代變了
(Gym) https://codeforces.com/gym/101190
(Luogu) https://www.luogu.com.cn/problem/P6967
(LOJ) https://loj.ac/p/6079
題解
想了一晚上,終于有點理解了,好神仙啊。
我只會純網絡流的做法,并不會線性規劃。
首先題意顯然是有一個序列每個位置可以選 \(0\) 或 \(1\),收益分別是 \(a_i\) 和 \(b_i\),且滿足每個長度為 \(m\) 的區間里選 \(1\) 的個數在 \([L,R]\) 內。
區間個數的限制似乎在網絡流中難以體現,于是有一種思路是把區間和點進行轉化。也就是我們有 \((n-m+1)\) 種區間,不妨設按照左端點編號,那么對于每個點,如果選了 \(1\) 會給編號在一個區間內的區間的選 \(1\) 個數增加 \(1\)(或者選 \(0\) 的個數減少 \(1\))。這個在網絡流中的體現是用一條邊從 \(i\) 指向 \((i+m)\),分走 \(1\) 的流量,后面再還回來。
那么就有了一個上下界費用流的建圖:建立源點 \(S\) 和 \(0,1,2,...,n-m+1\),連邊 \((S,0,[0,m],0),(i,i+1,[n-R,n-L],0),(\max(0,i-m),\min(n-m+1,i),[0,1],b_i-a_i)\),然后求 \(S\) 到 \((n-m+1)\) 的最大費用最大流,答案再加上 \(\sum^n_{i=1}a_i\). 一單位的流量流過 \((i,i+1)\) 代表選了 \(0\),否則代表選了 \(1\).
但這樣似乎并不優美??紤]優化成不帶上下界的費用流。
我們其實沒有必要拘泥于讓 \((i,i+1)\) 流過一單位流量代表選了 \(0\). 我們只要把 \(1\) 的選出來就好了!我們從源點往 \(0\) 連流量為 \(R\) 的邊,代表任何時刻不可能分走超過 \(R\) 的流量。然后再將 \((i,i+1)\) 的邊流量設置為 \(R-L\),意味著至少有 \(L\) 的流量要被分走。
于是做完了,時間復雜度 \(O(MFMC(n,2n))\).
代碼
太久沒寫網絡流了,甚至拉完板子后忘記了邊數要初始化成 \(1\)……
#include<bits/stdc++.h> #define llong long long #define mkpr make_pair #define x first #define y second #define iter iterator #define riter reverse_iterator #define y1 Lorem_ipsum_ #define tm dolor_sit_amet_ using namespace std;inline int read() {int x = 0,f = 1; char ch = getchar();for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}return x*f; }namespace NetFlow {const int N = 1002;const int M = 2002;const llong INF = 1e13;struct Edge{int u,v,nxt,w; llong c;} e[(M<<1)+3];int fe[N+3];llong dis[N+3];int que[N+5];bool inq[N+3];int lst[N+3];int n,m,en,s,t; llong mf,mc;void addedge(int u,int v,int w,llong c){en++; e[en].u = u,e[en].v = v,e[en].w = w,e[en].c = c;e[en].nxt = fe[u]; fe[u] = en;en++; e[en].u = v,e[en].v = u,e[en].w = 0,e[en].c = -c;e[en].nxt = fe[v]; fe[v] = en;}bool spfa(){for(int i=1; i<=n; i++) dis[i] = -INF;int hd = 1,tl = 2; que[1] = s; dis[s] = 0; inq[s] = true;while(hd!=tl){int u = que[hd]; hd++; if(hd>n+1) hd-=n+1;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(e[i].w>0&&dis[e[i].v]<dis[u]+e[i].c){dis[e[i].v] = dis[u]+e[i].c; lst[e[i].v] = i;if(!inq[e[i].v]){inq[e[i].v] = true;que[tl] = e[i].v; tl++; if(tl>n+1) tl-=n+1;}}}inq[u] = false;}return dis[t]!=-INF;}void calcflow(){int flow = 1e5;for(int u=t; u!=s; u=e[lst[u]].u){flow = min(flow,e[lst[u]].w);}for(int u=t; u!=s; u=e[lst[u]].u){e[lst[u]].w -= flow; e[lst[u]^1].w += flow;}mf += flow; mc += 1ll*flow*dis[t];}llong mfmc(int _n,int _s,int _t){n = _n,s = _s,t = _t; mf = 0,mc = 0ll;while(spfa()) {calcflow();} return mc;} } using NetFlow::addedge; using NetFlow::mfmc;const int mxN = 1000; int n,m,al,ar; llong a[mxN+3],b[mxN+3];int main() {n = read(),m = read(),ar = m-read(),al = read(); NetFlow::en = 1;for(int i=1; i<=n; i++) a[i] = read(); for(int i=1; i<=n; i++) b[i] = read();llong ans = 0ll;for(int i=1; i<=n; i++) ans += a[i];addedge(1,2,ar,0);for(int i=1; i<=n; i++){addedge(max(0,i-m)+2,min(n-m+1,i)+2,1,b[i]-a[i]);}for(int i=0; i<n-m+1; i++){addedge(i+2,i+1+2,ar-al,0);}ans += mfmc(n-m+3,1,n-m+1+2);printf("%lld\n",ans);for(int i=1; i<=n; i++){if(NetFlow::e[2*i+2].w==0) {printf("E");} else {printf("S");}}puts("");return 0; }總結
以上是生活随笔為你收集整理的Gym 101190D BZOJ 4842 Luogu P6967 LOJ #6071 [NEERC2016]Delight for a Cat (费用流)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NOI2020 前最后的日子
- 下一篇: Gym 101221I [WF2014]