%%% 神仙 tzc 爆切 arcE!
一眼 wll:源点连向所有零食 \(i\),容量为 \(a_i\);所有零食 \(i\) 连向所有小孩 \(j\),容量为 \(b_j\);所有小孩 \(j\) 连向汇点,容量为 \(c_j\)。跑最大流。但是这个图的边数是 1e10,存都存不下,就不会做了。
然后就是非常神仙的思路了 %%%%%:将最大流转化成最小割(u1s1 用最大流做最小割很正常,但是用最小割做最大流还真的没见过)。我们知道最小割要比最大流显式得多,所以在特殊构造的图里面最小割往往更好求。
先来扯这么一件事:很多人以为割的定义是一个边集使得割掉之后 \(s\to t\) 不连通,其实不然,这玩意叫做「割边集」;割的定义其实是对点集的一个划分 \(S,T\) 使 \(s\in S,t\in T\),\(S\to T\) 所有边的集合为一个割。但是很好的事情是:在边权都非负的图上,最小割等于最小割边集,这样我们就可以求更直观的最小割边集 instead of 定义比较棘手的最小割了。证明:显然所有割都是割边集,所以最小割 ≥ 最小割边集;对每个割边集,从 \(s\) 开始 dfs 显然到不了 \(t\),令所有到的节点集合为 \(S\),考虑割 \((S,V-S)\),这显然是原割边集去掉一些边,由于边权是正的,所以边权和不升,得到最小割 ≤ 最小割边集。得证。
有了这个思路就不算难了。设 \(a\) 边割掉的序列为 \(x\),\(c\) 边割掉的序列为 \(y\),此时最小割边集显然为 \(\sum\limits_{i=1}^{|x|}{a_{x_i}}+\sum\limits_{i=1}^{m}\begin{cases}c_i&i\in y\\(n-|x|)b_i&i\notin y\end{cases}\)。注意到右边的 sum 跟 \(x\) 具体是多少无关,只跟 \(|x|\) 有关,所以在 \(|x|\) 确定的情况下应该选尽可能小的 \(a_{x_i}\),那就排个序前缀和。考虑枚举 \(|x|\),右边那项最优决策显然是 \(\sum\limits_{i=1}^m\min(c_i,(n-|x|)b_i)\)。考虑随 \(|x|\) 变化维护这玩意,显然对每个 \(i\) 决策是单调的,即存在分界点使得一边全选 \(c_i\) 一边全选 \((n-|x|)b_i\)。那就预处理出所有分界点(除法上取整即可)存到对应位置 todo-list 里,随便搞就行了。不算排序,复杂度线性。
code#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=200010;
int n,m;
int a[N],b[N],c[N];
vector<int> chg[N];
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%lld",a+i);
for(int i=1;i<=m;i++)scanf("%lld",b+i);
for(int i=1;i<=m;i++)scanf("%lld",c+i);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)a[i]+=a[i-1];
int ans=inf,sum=0,now=0;
for(int i=1;i<=m;i++){
now+=b[i];
int x=(c[i]+b[i]-1)/b[i];
if(x>n)continue;
chg[n-x].pb(i);
}
for(int i=n;~i;i--){
ans=min(ans,a[i]+sum);
if(i){
for(int j=0;j<chg[i-1].size();j++){
int x=chg[i-1][j];
now-=b[x];
sum+=-(n-i)*b[x]+c[x];
}
sum+=now;
}
}
cout<<ans;
return 0;
}