Preface:

这是生平第一道现场 AC 的 arc E,也生平第一次经历了 performance \(\ge 2800\)​,甚至还生平第一次被 hb 拉到会议里讲题,讲的就是这个题,然鹅比较尬的一点是我不知道腾讯会议开了白板之后不能看到电脑,导致我的 typora 没人能看到……所以就暂且把我 typora 的内容整了整改成了一篇题解(​

题意:

  • 有 \(n\) 种零食,第 \(i\) 种零食有 \(a_i\)​ 个。
  • 有 \(m\) 个人领这些零食,第 \(i\) 个人最多领 \(b_i\)​ 个同种零食
  • 第 \(i\) 个人领零食的总数不能超过 \(c_i\)
  • 求最多能分出去多少零食
  • \(n,m\le 2\times 10^5,a_i\le 10^{12},b_i\le 10^7\)​

首先考虑网络流建图,我们新建一个源点 \(S\) 和汇点 \(T\),然后考虑将零食看作左部点 \(X_i\),人看作右部点 \(Y_i\),那么我们显然可以建出以下几类边:

  • 对每个 \(i\in[1,n]\) 连边 \(S\to X_i\),容量 \(a_i\)
  • 对每个 \(i\in[1,n],j\in[1,m]\) 连边 \(X_i\to Y_j\),容量 \(b_j\)
  • 对每个 \(i\in[1,m]\) 连边 \(Y_i\to T\),容量 \(c_i\)

然后跑最大流就是答案。不过显然直接建图复杂度爆炸——甚至连图都存不下,因此考虑这样一个套路:使用最大流&最小割定理转化为最小割问题。也就是我们要割掉权值最小的边集使得 \(S,T\)​ 不连通。下记 \(S\to X_i\) 为第一类边,\(X_i\to Y_j,Y_i\to T\)​ 分别记作第二、三类边。

这个问题就可以贪心求解了。考虑枚举保留多少个一类边,记作 \(x\),那注意到此题的一个性质,所有左部点(也就是 \(X_i\))在我们钦定割/不割掉与 \(S\) 相连的边后就是等价的了,也就是说只有切掉的个数有意义,具体切的是哪些边对后面(也就是切二、三类边的代价)的计算没有影响。因此我们肯定会贪心地割掉最小的 \(n-x\) 条 一类边,排序+前缀和求解即可。接下来考虑割掉二、三类边的代价,对于一个 \(Y_j\),目前有用的边肯定只剩下 \(x\) 条与 \(Y_j\) 相连的二类边和 \(Y_j\) 连向汇点的三类边,显然要么二类边全删,要么三类边全删,因此删掉与 \(j\) 有关的边的代价是 \(\min(c_j,b_j·x)\)。将所有右部点按照 \(\dfrac{c_j}{b_j}\) 排序后 \(\min\) 取到 \(c_j\) 的部分一定是一段前缀,\(\min\) 取到 \(b_j·x\) 的部分肯定是对应部分的一个补集,也就是一段后缀。我们在枚举 \(x\) 的过程中 two pointers 找出这段前缀,然后预处理出 \(b,c\) 的前缀和即可 \(\mathcal O(1)\) 计算贡献。

时间复杂度 \(n\log n\)(如果 \(n,m\) 视作同阶),注意精度,直接比较 double 可能会获得 \(\text{AC}\times26,\text{WA}\times1\) 的好成绩。

const int MAXN=2e5;
int n,m,ord[MAXN+5];
ll a[MAXN+5],b[MAXN+5],c[MAXN+5];
ll suma[MAXN+5],sumb[MAXN+5],sumc[MAXN+5];
bool cmp(int x,int y){return 1ull*c[x]*b[y]<1ull*b[x]*c[y];}
int main(){
scanf("%d%d",&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]);
for(int i=1;i<=m;i++) ord[i]=i;
sort(a+1,a+n+1);sort(ord+1,ord+m+1,cmp);
for(int i=1;i<=n;i++) suma[i]=suma[i-1]+a[i];
for(int i=1;i<=m;i++) sumb[i]=sumb[i-1]+b[ord[i]];
for(int i=1;i<=m;i++) sumc[i]=sumc[i-1]+c[ord[i]];
ll res=1e18;
for(int i=0;i<=n;i++){
int l=1,r=m,p=0;
while(l<=r){
int mid=l+r>>1;
if(1ll*b[ord[mid]]*i<=c[ord[mid]]) r=mid-1;
else p=mid,l=mid+1;
} //printf("%d %d\n",i,p);
chkmin(res,suma[n-i]+sumc[p]+1ll*(sumb[m]-sumb[p])*i);
} printf("%lld\n",res);
return 0;
}

Atcoder Regular Contest 125 E - Snack(最小割转化+贪心)的更多相关文章

  1. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  2. AtCoder Regular Contest 093

    AtCoder Regular Contest 093 C - Traveling Plan 题意: 给定n个点,求出删去i号点时,按顺序从起点到一号点走到n号点最后回到起点所走的路程是多少. \(n ...

  3. AtCoder Regular Contest 094

    AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几 ...

  4. AtCoder Regular Contest 095

    AtCoder Regular Contest 095 C - Many Medians 题意: 给出n个数,求出去掉第i个数之后所有数的中位数,保证n是偶数. \(n\le 200000\) 分析: ...

  5. AtCoder Regular Contest 102

    AtCoder Regular Contest 102 C - Triangular Relationship 题意: 给出n,k求有多少个不大于n的三元组,使其中两两数字的和都是k的倍数,数字可以重 ...

  6. AtCoder Regular Contest 096

    AtCoder Regular Contest 096 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个 ...

  7. AtCoder Regular Contest 098

    AtCoder Regular Contest 098 C - Attention 题意 给定一个只包含"E","W"字符串,可以花一的花费使他们互相转换.选定 ...

  8. AtCoder Regular Contest 099

    AtCoder Regular Contest 099 C - Minimization 题意 题意:给出一个n的排列.每次操作可以使一段长度为K的连续子序列变成该序列的最小数.求最少几次使得整个数列 ...

  9. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...

随机推荐

  1. OO面向对象第三次作业总结

    面向对象第三次作业总结 一.JML基础梳理及工具链 注释结构 行注释://@annotation 块注释:/*@ annotation @*/ 两种注释都是放在被注释部分上面. 常见表达式 原子表达式 ...

  2. Noip模拟33垫底反思 2021.8.8

    T1 Hunter 考场上没写$%p$挂了25分.也是很牛皮,以后打完过了样例一定要检查 因为样例太小了......很容易忘记%%%% 正解随便手模就出来了. 1 #include<bits/s ...

  3. 零基础学习Linux所必备的七大习惯

    对于很多Linux初学者来说,在刚开始使用linux系统时会感到很多的不适.这里为大家整理了自己以前linux入门时别人告诉我的七个习惯.我相信如果你运用了这七个习惯,在你使用Linux时你会感觉更安 ...

  4. 最详细的windows10系统封装教程

    目录 自定义封装(定制)windows10教程 关于本教程及用到的工具的声明 第一阶段: 封装前的各种环境准备 安装vmware 创建虚拟机 对虚拟机进行分区 配置好BIOS 为虚拟机安装window ...

  5. linux c语言 rename的用法-rename() does not work across different mount points, even if the same file system is mounted on both

    最近在一个项目上执行文件的搬移功能时发现总是失败,临时录像文件存放于emmc的/tmp/目录下,当录像完成时候则调用rename企图将此文件搬到/mnt/sdcard/mmcblk1p1/(这是外置的 ...

  6. Luogu P2467 [SDOI2010]地精部落 | 神奇的dp

    题目链接 DP 题目大意:给定一个数n,求1~n这n个整数的所有排列中有多少个波动数列,将这个数量%p后输出. 什么是波动数列呢?顾名思义,就是一个大.一个小.一个大.一个小--或者是一个小.一个大. ...

  7. 记录一个很傻的错误(C++)

    使用的vscode写代码,导入了vector,memory,然后忘了导入string.但是代码中能够提示std::string也就让我忘了导入string.然后就莫名其妙的报错了.找了很久的错.记录下 ...

  8. JMeter学习笔记--关联

    1.什么是关联? 本次请求需要的数据,需要上一步的请求返回给提供的过程. 2.JMeter关联中常用的两种方式 正则表达式提取器 正则表达式提取器用于对页面任何文本的提取,提取的内容是根据正则表达式在 ...

  9. CommonJS与ES6 Module的使用与区别

    CommonJS与ES6 Module的使用与区别 1. CommonJS 1.1 导出 1.2 导入 2. ES6 Module 2.1 导出 2.2 导入 3. CommonJS 与 ES6 Mo ...

  10. Windows内核中的CPU架构-8-任务段TSS(task state segment)

    Windows内核中的CPU架构-8-任务段TSS(task state segment) 任务段tss(task state segment)是针对于CPU的一个概念. 举一个简单的例子,你一个电脑 ...