小清新网络流优化题
首先不难想到一个 trivial 的网络流模型,即建立源点 \(S\) 和汇点 \(T\)
对于每个食物 \(i\),连 \(S\to i\),容量为 \(A_i\) 的边;对于每个人 \(j\),连 \(j\to T\),容量为 \(C_j\) 的边;同时所有食物向每个人 \(j\) 连容量为 \(B_j\) 的边
直接跑 Dinic 复杂度显然爆了,但这个图具有很强的性质,考虑手动找出它的最大流
首先用最大流最小割定理转为求最小割,枚举最后要断掉和 \(S\) 相邻的 \(x\) 条边
手玩发现由于左边每个点向右连出的边都相同,因此显然是断开最小的 \(x\) 条边
再考虑此时右边的每个点 \(j\),要么断开它和 \(T\) 的边,代价为 \(C_j\);要么断开中间的边,代价为 \((n-x)\times B_j\)
考虑从小到大枚举 \(x\),把人按照 \(\frac{C_j}{B_j}\) 排序后 two pointers
扫一遍即可
#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
typedef __int128 i128;
const int N=200005;
struct ifo
{
int b,c;
friend inline bool operator < (const ifo& A,const ifo& B)
{
return i128(A.c)*B.b>i128(A.b)*B.c;
}
}p[N]; int n,m,a[N];
signed main()
{
scanf("%lld%lld",&n,&m);
for (RI i=1;i<=n;++i) scanf("%lld",&a[i]);
for (RI i=1;i<=m;++i) scanf("%lld",&p[i].b);
for (RI i=1;i<=m;++i) scanf("%lld",&p[i].c);
sort(a+1,a+n+1); sort(p+1,p+m+1);
int ans=1e18,suma=0,sumb=0,sumc=0;
for (RI i=1;i<=m;++i) sumc+=p[i].c;
for (RI i=0,j=1;i<=n;++i)
{
while (j<=m&&(n-i)*p[j].b<=p[j].c)
sumb+=p[j].b,sumc-=p[j].c,++j;
suma+=a[i]; ans=min(ans,suma+(n-i)*sumb+sumc);
}
return printf("%lld",ans),0;
}
标签:Snack,const,int,ARC125E,i128,include,ifo,define
From: https://www.cnblogs.com/cjjsb/p/18359640