Gym 101190D BZOJ 4842 Luogu P6967 LOJ #6071 [NEERC2016]Delight for a Cat (費用流)
阿新 • • 發佈:2021-01-08
題目連結
(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)\)
那麼就有了一個上下界費用流的建圖:建立源點 \(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\) 的選出來就好了!我們從源點往 \(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;
}