希望更丰富的展现?来我搭建的网站看看

Problem

\(n\) 个人乘船过河,该船容纳人的上限为 \(R\),并且需要至少 \(L\) 个人才能操作。每次过河时所有人都需划船,使船上所有人的耐力值减 \(1\)。最初每个人的耐力值为 \(h_i\)。

判断是否所有人都能过河。

\(1\le L<R\le n\le 5\times 10^5\)

\(1\le h_i\le 5\times 10^5\)

Solution

每个人都需要花费至少一点体力来过河。有多余的体力的话可以用于划来回,花费两点耐力当船夫。所以一个人最多可以当 \(a_i=\lfloor\frac{h_i-1}{2}\rfloor\) 次船夫。

贪心,每次过河可以送 \(R-L\) 个人过河,最后一趟 \(R\) 个人全部下船,所以至少需要来回 \(T=\lceil\frac{n-R}{R-L}\rceil\) 次来回,每个来回都需要 \(L\) 名船夫。

现在问题转化为:每次从 \(a_i\) 中选 \(L\) 个数字全部减 \(1\),问能否进行 \(T\) 次这样的操作?

直接上结论:如果 \(\sum_{i=1}^n\min(a_i,T)\ge T\times L\),则可以。反之不能。

该条件的必要性是很明显的:对于每个 \(a_i\),只有 \(\le T\) 的部分才是可能有效的。至少要所有 \(a_i\) 的有效部分 \(\min(a_i,T)\) 之和超过操作 \(T\) 次的总消耗 \(T\times L\) 才有可能有用。

该条件的充分性用下述贪心证明:

贪心:每次选择最大的 \(L\) 个 \(a_i\) 进行操作。

此时操作一次结束之后的数组为 \(a_i^\prime\),对于 \(a_i^\prime\) 还需要进行 \(T-1\) 次操作,条件 \(\sum_{i=1}^n\min(a_i,T)\ge T\times L\) 等价于 \(\sum_{i=1}^n\min(a_i^\prime,T-1)\ge (T-1)\times L\)。

继续等价于:执行了 \(T-1\) 次操作之后的 \(a_i^{(T-1)}\) 需要满足 \(\sum_{i=1}^n\min(a_i^{(T-1)},1)\ge L\),也就是此时需要在 \(a_i^{(T-1)}\) 中需要至少有 \(L\) 个正数,才能满足可以进行一次操作。这个条件显然是充分必要的。

由数学归纳法可知正确性。

时间复杂度 \(O(n)\)。

Code

#define N 500010

LL n,L,R,T;
LL h[N],a[N]; int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
// cin>>t;
while(t--)
{
cin>>n>>L>>R;
for(int i=1;i<=n;i++) cin>>h[i],a[i]=(h[i]-1)/2;
T=(n-R+(R-L-1))/(R-L);//ceil
LL sum=0;
for(int i=1;i<=n;i++)
{
sum+=min(T,a[i]);
}
if(sum<T*L) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}

Extra

这个问题总感觉很常见呢?但是居然没有想过该如何解决。

每次从 \(a_i\) 中选 \(L\) 个数字全部减 \(1\),问能否进行 \(T\) 次这样的操作?

假如换一种问法:

每次从 \(a_i\) 中选 \(L\) 个数字全部减 \(1\),问最多能进行多少次这样的操作?

一种很显然的做法就是可以二分答案,时间复杂度为 \(O(n\log(\frac{\sum a}{L}))\),时间复杂度其实是还能接受的。但是赛时 langod 就是这抱着“先求出最多能够进行的操作数量再与 \(T\) 进行比较”的想法,找到了一种直接求出“最大操作数”的算法,时间复杂度为 \(O(n\log (n))\)。算法是正确的,但是过程稍微复杂一点:

  1. 对 \(a_i\) 升序排序。
  2. 在 \([n-L+1,n]\) 的左右插入无限高的挡板,现在 \([n-L+1,n]\) 变成了一段容器的底部。
  3. 假想 \([1,n-L]\) 这一段“液化”了,也就是可以流动,其面积为 \(\displaystyle water=\sum_{i=1}^{n-L} a_i\)。
  4. 将 \([1,n-L]\) 这一段“液体”全部倒在 \([n-L+1,n]\) 段上。液体会优先填补靠左的更低的部分,逐渐向上抬高水面的同时向右覆盖。
  5. 最后液体上表面距离地面的高度 \(H\) 即为答案。

正确性可由上结论推导。假设水只覆盖了 \([n-L+1,j]\) 段,长度为 \(j-(n-L+1)\),高度为 \(H\),则现在我们需证明这一段能够进行 \(H\)​ 次操作。

由于 \(\sum_{i=1}^n\min(a_i,T)\ge T\times L\Rightarrow 可进行T次操作\),

而 \(\forall i\in[1,j],a_i\le H\),所以有

\[\begin{align}
\sum_{i=1}^j \min(a_i,H)=& \sum_{i=1}^j a_i\\
=&[n-L+1,j]段的面积\\
=&H\times [j-(n-L+1)]

\end{align}
\]

\(\sum_{i=1}^j \min(a_i,H)=\sum_{i=1}^j a_i=[n-L+1,j]段的面积=H\times [j-(n-L+1)]\)

具体在模拟计算时可以尝试用 \(water\) 从下到上逐渐一层层的填补空缺部分,直到无法向右上溢为止。

#define N 500010

LL n,L,R,T;
LL h[N],a[N];
LL ans;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
// cin>>t;
while(t--)
{
cin>>n>>L>>R;
for(int i=1;i<=n;i++) cin>>h[i],a[i]=(h[i]-1)/2;
T=(n-R+(R-L-1))/(R-L); sort(a+1,a+n+1);
a[n+1]=1000000000ll;
LL water=0;
for(int i=1;i<=n-L;i++) water+=a[i];
for(int i=1;i<=L;i++)
{
int j=i+(n-L);
if(water>=(a[j+1]-a[j])*i)
{
water-=(a[j+1]-a[j])*i;
}
else
{
ans=a[j];
ans+=water/i;
break;
}
}
// cout<<ans<<endl;
if(ans>=T) cout<<"Yes"<<endl;
else cout<<"No"<<endl; }
return 0;
}

2024牛客多校3A Bridging the Gap 2的更多相关文章

  1. 2019牛客多校第一场 I Points Division(动态规划+线段树)

    2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...

  2. 牛客多校第一场 B Inergratiion

    牛客多校第一场 B Inergratiion 传送门:https://ac.nowcoder.com/acm/contest/881/B 题意: 给你一个 [求值为多少 题解: 根据线代的知识 我们可 ...

  3. 2019牛客多校第二场 A Eddy Walker(概率推公式)

    2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...

  4. 牛客多校第三场 F Planting Trees

    牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...

  5. 牛客多校第三场 G Removing Stones(分治+线段树)

    牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...

  6. 牛客多校第四场sequence C (线段树+单调栈)

    牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...

  7. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  8. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  9. 2019年牛客多校第一场B题Integration 数学

    2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...

  10. 2020牛客多校第八场K题

    __int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...

随机推荐

  1. 记录-C#给图片增加文字

    业务需要动态给图片增加文字(书本的封面图片),修改字体大小.字体.颜色.控制位置 测试代码: 1 string path = @"E:\cover.png"; 2 3 Bitmap ...

  2. TPC-H 研究和优化尝试

    TPC-H测试提供了8张表,最近做这个测试,记录下过程中的关键点备忘. 1.整体理解TPC-H 8张表 2.建立主外键约束后测试22条SQL 3.分区表改造,确认分区字段 4.重新测试22条SQL 5 ...

  3. NumPy学习9

    今天学习了NumPy排序和搜索功能 17, NumPy排序和搜索功能 numpy_test9.py : import numpy as np ''' 17, NumPy排序和搜索功能 NumPy 提供 ...

  4. 【Azure Fabric Service】分享使用Visual Studio 2022发布中国区Service Fabric服务应用的办法

    问题描述 使用Visual Studio 2022如何发布Service Fabric到中国区云服务呢? 因为使用VS2022中的插件无法创建Service Fabric Cluster服务. 那么, ...

  5. Linux下启动Oracle命令

    1.进入LInux,切换到Oracle用户权限,输入数据库密码.su - oracle    1在这里插入图片描述2.输入sqlplus "/as sysdba"    1在这里插 ...

  6. 正则表达式--java进阶day06

    1.正则表达式 2.正则表达式的规则.使用 3.字符类讲解 如图,单独一个a满足正则表达式的规则,所以返回true 当删去[]后,正则表达式中的规则就会变为必须是abc,否则不满足条件,即使有一个a ...

  7. Debian 下安装 Nginx

    Debian 下安装 Nginx 非常容易. apt update apt install nginx 输入以下命令查看是否可以正常访问, 顺便验证下安装是否成功. curl -I 127.0.0.1 ...

  8. 《数组》--DAY1--二分查找

    分治算法--二分查找(返回下标) 1.定义:在有序列表中,每次查找范围折半 列表若存在重复元素,返回下标不唯一 优点:比较次数少,速度快,性能好:缺点:要求列表有序 注意区分while(left &l ...

  9. python,获取当前日期且以当前日期为名称创建文件名

    爬虫爬取信息时,需要把爬取的内容存到txt文档中,且爬虫是每天执行,以日期命名能避免出现名称重复等问题,解决方法如下 import time import os import sys path = o ...

  10. Robot Framework自定义关键字

    需求分析: 如下图,诸多步骤中可能共用某些共同的步骤,比如都需要登录会员 此,可以把登录的操作写成模块化,插入其他脚本供其他脚本调用,如此可以节省不少脚本量 上图为会员登录的操作. 具体实施如下: 1 ...