【YBT2023寒假Day7 B】打怪兽(cdq分治)(斜率优化)

文章讨论了一个与游戏策略相关的算法问题,其中涉及对怪物的攻击力和血量进行处理,通过计算最小血量来战胜所有怪物。关键策略包括将血量转换为击败次数,解决经典排序问题,以及利用CDQ分治和斜率优化来降低复杂度。代码部分展示了实现这一算法的C++程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

打怪兽

题目链接:YBT2023寒假Day7 B

题目大意

有 n 个怪,每个怪有攻击力和血量。
你每次可以选一个怪打 b 的伤害,如果一个怪的血量小于等于 0 就死了。
然后每次你打完之后所有活着的怪会各打你一次。
一开始你可以选两个怪秒杀,问你打死所有怪需要的最小血量。

思路

首先把血量 c c c 改成要打死的次数 ( c + b − 1 ) / b (c+b-1)/b (c+b1)/b(就是 ⌈ c b ⌉ \left\lceil\dfrac{c}{b}\right\rceil bc

首先不考虑秒杀,其实是一个经典的排序问题。
(你直接看谁先就直接假设只有这两个怪,谁先打掉的血少谁就放前面)
(至于原因把式子列一下就看得出来)

接下来考虑看秒杀,考虑秒掉之后减少的费用。
我们假设 i , j ( i < j ) i,j(i<j) i,j(i<j) 为秒掉的两个,那减少的费用是:
a i ( ∑ k = 1 i c k − 1 ) + c i ∑ k = i + 1 n a k + a j ( ∑ k = 1 j c k − c i − 1 ) + c j ∑ k = j + 1 n a k a_i(\sum\limits_{k=1}^ic_k-1)+c_i\sum\limits_{k=i+1}^na_k+a_j(\sum\limits_{k=1}^jc_k-c_i-1)+c_j\sum\limits_{k=j+1}^na_k ai(k=1ick1)+cik=i+1nak+aj(k=1jckci1)+cjk=j+1nak
(第一个和第三个是它打你的次数减少了,第二个和第四个是你打它的时间省了使得后面的怪打你的次数少了)

会发现可以写成 A i + B j − a j c i A_i+B_j-a_jc_i Ai+Bjajci 的形式(其实 A i , B i A_i,B_i Ai,Bi 是同一个数组,都是 a i ( ∑ k = 1 i c i − 1 ) + c i ∑ k = i + 1 n a i a_i(\sum\limits_{k=1}^ic_i-1)+c_i\sum\limits_{k=i+1}^na_i ai(k=1ici1)+cik=i+1nai,前缀后缀预处理一下就行)

那如果我们枚举一个 j j j,它就会变成要求 A i − a j c i A_i-a_jc_i Aiajci 的最大值,那这个东西是线段,可以维护上凸壳 j j j 变大,在凸壳上二分(也可以直接指针找)最大值加上点。
但是一个问题是 a , c a,c a,c 不能同时递增。

于是这种两个变量的考虑通过 cdq 分治减少一个。
大概是给前面一半按 c i c_i ci 排序,后面一半按 a i a_i ai 排序。
然后推 A i 1 − a j c i 1 > A i 2 − a j c i 2 A_{i1}-a_jc_{i1}>A_{i2}-a_jc_{i2} Ai1ajci1>Ai2ajci2 这个式子得到比较方式。(就是斜率优化)

代码

#include<cstdio>
#include<iostream>
#include<algorithm> 
#define ll long long

using namespace std;

const int N = 3e5 + 100;
struct node {
	ll a, d, A;
}a[N];
int n, b, tot;
ll ans, sta[N];

bool cmp(node x, node y) {
	return x.a * (x.d - 1) + y.a * (x.d + y.d - 1) < y.a * (y.d - 1) + x.a * (y.d + x.d - 1);
}

bool cmpd(node x, node y) {return x.d < y.d;}
bool cmpa(node x, node y) {return x.a < y.a;}

void cdq(int l, int r) {
	if (l == r) return ;
	int mid = (l + r) >> 1;
	cdq(l, mid); cdq(mid + 1, r);
	sort(a + l, a + mid + 1, cmpd); sort(a + mid + 1, a + r + 1, cmpa);
	tot = 1; int L = 1; sta[0] = sta[1] = 0;
	for (int i = l; i <= mid; i++) {
		while (L < tot && (a[i].A - a[sta[tot]].A) * (a[sta[tot]].d - a[sta[tot - 1]].d) >= (a[sta[tot]].A - a[sta[tot - 1]].A) * (a[i].d - a[sta[tot]].d)) tot--;
		sta[++tot] = i;
	}
	for (int i = mid + 1; i <= r; i++) {
		while (L < tot && (a[sta[L + 1]].A - a[sta[L]].A) >= a[i].a * (a[sta[L + 1]].d - a[sta[L]].d)) L++;
		ans = max(ans, a[i].A + a[sta[L]].A - a[i].a * a[sta[L]].d);
	}
}

int main() {
	freopen("fittest.in", "r", stdin);
	freopen("fittest.out", "w", stdout);
	
	scanf("%d %d", &n, &b);
	for (int i = 1; i <= n; i++) {
		scanf("%lld %lld", &a[i].a, &a[i].d); a[i].d = (a[i].d + b - 1) / b;
	}
	sort(a + 1, a + n + 1, cmp);
	
	ll all = 0, tmp = 0;
	for (int i = 1; i <= n; i++) {
		tmp += a[i].d;
		all += a[i].a * (tmp - 1);
		a[i].A = a[i].a * (tmp - 1);
	}
	tmp = 0;
	for (int i = n; i >= 1; i--) {
		a[i].A += a[i].d * tmp;
		tmp += a[i].a;
	}
	
	cdq(1, n);
	printf("%lld", all - ans);
	
	return 0;
}
<think>我们正在讨论如何卸载挂载点。用户提到挂载点是 `/run/media/ybt/CentOS 7 x86_64`,注意路径中有空格,因此需要特别处理。 卸载挂载点通常使用 `umount` 命令(注意不是unmount,而是umount)。由于路径包含空格,我们需要用引号将路径括起来,或者使用反斜杠转义空格。 有两种方法: 1. 使用双引号:`sudo umount "/run/media/ybt/CentOS 7 x86_64"` 2. 或者使用反斜杠转义空格:`sudo umount /run/media/ybt/CentOS\ 7\ x86_64` 注意:通常需要管理员权限,所以使用 `sudo`。 如果遇到设备忙(device is busy)的错误,可能是因为有进程正在使用挂载点内的文件。我们可以尝试以下方法: - 关闭所有使用该挂载点的程序。 - 使用 `lsof` 命令查看哪些进程在使用:`lsof "/run/media/ybt/CentOS 7 x86_64"`,然后结束相关进程。 - 如果不想手动结束进程,也可以使用 `umount` 的懒卸载(lazy unmount)选项:`sudo umount -l "/run/media/ybt/CentOS 7 x86_64"`,这样会先断开挂载,等设备不再繁忙时再清理资源。 另外,如果该挂载点是通过文件管理器自动挂载的(比如插入U盘或光盘),那么也可以尝试在文件管理器中右键点击该设备并选择“弹出”(Eject)来卸载。 但是,请注意,卸载(umount)和弹出(eject)是两个不同的操作。对于光盘设备,弹出操作除了卸载还会弹出光驱托盘,但对于U盘或移动硬盘,通常卸载和弹出效果类似。不过,在命令行中我们通常使用 `umount`。 步骤总结: 1. 尝试使用 `sudo umount` 命令卸载。 2. 如果设备忙,使用 `lsof` 查看并结束进程,或者使用懒卸载。 3. 卸载成功后,挂载点目录将变为空,可以安全移除设备。 注意:卸载后,该挂载点目录(`/run/media/ybt/CentOS 7 x86_64`)仍然存在,但里面不再有挂载的文件系统。这是正常的,因为该目录是系统临时创建的挂载点,通常由自动挂载服务(如udisks2)管理,在卸载后可以不用管它,下次挂载时可能会重新使用或自动删除。 因此,我们可以这样操作: 方法一(推荐): ``` sudo umount "/run/media/ybt/CentOS 7 x86_64" ``` 方法二(如果设备忙): ``` sudo umount -l "/run/media/ybt/CentOS 7 x86_64" ``` 如果上述命令仍然无法卸载,可以尝试查看设备是否被锁定,或者重启计算机(不推荐,应作为最后手段)。 另外,如果这个挂载点是通过图形界面挂载的,也可以尝试在图形界面中卸载(例如在文件管理器中右键点击该设备并选择“弹出”)。 最后,请注意:卸载操作不会删除设备上的数据,只是断开文件系统与目录的关联。 根据用户提供的引用,我们并没有直接关于卸载命令的内容,但我们可以根据Linux系统管理知识回答。 生成相关问题: 1. 如何查看当前系统中所有的挂载点? 2. 如果卸载时遇到“device is busy”错误,有哪些解决方法? 3. 如何永久性地避免某个设备被自动挂载? 4. 在Linux中,挂载和卸载文件系统的基本原理是什么?</think>### 如何卸载 `/run/media/ybt/CentOS 7 x86_64` 挂载点 #### 步骤详解: 1. **确认挂载点** 使用 `df -h` 或 `mount | grep CentOS` 命令确认挂载点的设备路径(如 `/dev/sdb1`),确保卸载目标正确: ```bash df -h | grep "CentOS 7 x86_64" ``` 2. **卸载挂载点** 由于路径包含空格,需用引号包裹路径或使用转义符: ```bash sudo umount "/run/media/ybt/CentOS 7 x86_64" # 推荐方式 # 或 sudo umount /run/media/ybt/CentOS\ 7\ x86_64 # 转义空格 ``` 3. **处理设备繁忙问题** 若提示 `target is busy`: - **查找占用进程**: ```bash sudo lsof +D "/run/media/ybt/CentOS 7 x86_64" ``` 结束相关进程(如 `kill -9 PID`)或关闭访问文件的程序。 - **强制卸载**(慎用): ```bash sudo umount -l "/run/media/ybt/CentOS 7 x86_64" # -l 表示延迟卸载 ``` 4. **验证卸载结果** 再次运行 `df -h` 确认挂载点已消失: ```bash df -h | grep "CentOS 7 x86_64" # 若无输出则表示成功 ``` #### 关键说明: - **权限要求**:必须使用 `sudo` 获取管理员权限。 - **路径空格处理**:Linux 将空格视为分隔符,必须用引号或 `\` 转义。 - **安全卸载**:卸载仅解除目录与设备的关联,**不会删除原始数据**。 - **自动挂载**:该路径由系统自动创建(如插入U盘时),卸载后目录可能保留为空文件夹,可安全忽略[^1]。 #### 示例命令流程: ```bash $ df -h | grep CentOS /dev/sdc1 15G 0% /run/media/ybt/CentOS 7 x86_64 $ sudo umount "/run/media/ybt/CentOS 7 x86_64" $ df -h | grep CentOS # 无输出即成功 ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值