传送门:vijos1891
题解
设
x
i
=
1
/
0
x_i=1/0
xi=1/0分别表示第
i
i
i天请假/不请假,存在不等式:
x
1
+
x
2
+
.
.
.
+
x
n
≤
k
x_1+x_2+...+x_n\leq k
x1+x2+...+xn≤k
x
2
+
x
3
+
.
.
.
+
x
n
+
1
≤
k
x_2+x_3+...+x_{n+1}\leq k
x2+x3+...+xn+1≤k
⋮
\vdots
⋮
x
2
n
+
1
+
.
.
.
+
x
3
n
≤
k
x_{2n+1}+...+x_{3n}\leq k
x2n+1+...+x3n≤k
增加调节变量:
x
1
+
x
2
+
.
.
.
+
x
n
+
y
1
=
k
x_1+x_2+...+x_n+y_1=k
x1+x2+...+xn+y1=k
x
2
+
x
3
+
.
.
.
+
x
n
+
1
+
y
2
=
k
x_2+x_3+...+x_{n+1}+y_2=k
x2+x3+...+xn+1+y2=k
⋮
\vdots
⋮
x
2
n
+
1
+
.
.
.
+
x
3
n
+
y
2
n
+
1
=
k
x_{2n+1}+...+x_{3n}+y_{2n+1}=k
x2n+1+...+x3n+y2n+1=k
上式-下式:
x
1
+
y
1
=
x
n
+
1
+
y
2
x_1+y_1=x_{n+1}+y_2
x1+y1=xn+1+y2
⋮
\vdots
⋮
x
2
n
+
y
2
n
=
x
3
n
+
y
2
n
+
1
x_{2n}+y_{2n}=x_{3n}+y_{2n+1}
x2n+y2n=x3n+y2n+1
另有:
k
=
x
1
+
x
2
+
.
.
.
+
x
n
k=x_1+x_2+...+x_n
k=x1+x2+...+xn
x
2
n
+
1
+
.
.
.
+
x
3
n
=
k
x_{2n+1}+...+x_{3n}=k
x2n+1+...+x3n=k
发现每个变量都分别在等式左右出现了一次。
类似于网络流流入流出:
于是将等号看做点,等式左边看做流入流量,右边看做流出流量。两个
k
k
k分别看做源汇点,跑最小费用最大流即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+100;
const int inf=2e9;
int n,ky,S,T,tot=1,a[650],vis[2020],dis[2020];
int head[2020],to[N],nxt[N],w[N],ct[N],cost;
deque<int>Q;
char c;
template<class TT>
inline void rd(TT &x)
{
c=getchar();x=0;int f=0;
for(;!isdigit(c);c=getchar()) if(c=='-') f=1;
for(;isdigit(c);c=getchar()) x=x*10+(c^48);
if(f) x=-x;
}
inline void lk(int u,int v,int vv,int cc){
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;ct[tot]=cc;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;ct[tot]=-cc;
}
inline bool spfa()
{
int i,j,x;
for(i=1;i<T;++i) dis[i]=-inf,vis[i]=0;
vis[T]=1;dis[T]=0;Q.push_back(T);
while(!Q.empty()){
x=Q.front();Q.pop_front();
for(i=head[x];i;i=nxt[i]){
j=to[i];if(!w[i^1] || dis[j]>=dis[x]-ct[i]) continue;
dis[j]=dis[x]-ct[i];
if(!vis[j]){
if(Q.empty() || dis[Q.front()]>=dis[j]) Q.push_back(j);
else Q.push_front(j);
}
}
vis[x]=0;
}
return dis[S]>-inf;
}
inline int dfs(int x,int f)
{
vis[x]=1;
if(x==T) return f;
int i,j,res,ss=0;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vis[j] || (!w[i]) || dis[j]!=dis[x]-ct[i]) continue;
res=dfs(j,min(f-ss,w[i]));if(!res) continue;
ss+=res;w[i]-=res;w[i^1]+=res;cost+=res*ct[i];
if(ss==f) return f;
}
if(!ss) dis[x]=-inf;
return ss;
}
int main(){
int i,j,ix,iy,iz,iu,lim;
rd(n);rd(ky);
lim=(n<<1)+n;
for(i=1;i<=lim;++i) rd(a[i]);
S=(n<<1)+3;T=S+1;
for(i=1;i<=n;++i) lk(i,i+n,1,a[i+n]);
for(ix=(n<<1)+1,i=1;i<=n;++i) lk(ix,i,1,a[i]);
for(lim=(n<<1),ix++,i=n+1;i<=lim;++i) lk(i,ix,1,a[n+i]);
for(i=1;i<lim;++i) lk(i,i+1,ky,0);
lk(lim+1,1,ky,0);lk(lim,lim+2,ky,0);
lk(S,lim+1,ky,0);lk(lim+2,T,ky,0);
for(;spfa();){
for(vis[T]=1;vis[T];){
for(i=1;i<=T;++i) vis[i]=0;
dfs(S,inf);
}
}
printf("%d\n",cost);
}