CF1791G2 Teleporters (Hard Version) 题解
CF1791G2 Teleporters (Hard Version) 题解
题目大意
题意挺清楚的,给个传送门吧。
分析
比较简单的贪心题,很容易就能看出来是贪心,也很容易就能看出来贪什么。
我没做简单版(Teleporters (Easy Version)),但是我去看了一眼。那个也非常简单,不过提供了一点点思路。虽然提供的东西不多,我还是顺便讲一下吧。
那道题和这道题基本一样,不过传送门只能传到起点,即 号点。所以很容易想到,对于每个点算一下使用当前点的传送器所需要的代价 , 该点到 号点的距离,然后贪心用最小的即可。
对于这道题,我们不能这么做,因为对于离 号点远但离 号点近的点,明显跳到 号点再过去更优。
但是我们很容易想到,既然每次(除了第一次)可以从 号点开始,也可以从 号点开始,那么我们可以把使用这个传送器的代价 设为 ,然后贪心。
所以我们主要考虑的是,怎么排除掉第一次的硬性规定(即必须从 号点开始走)。
题解
我们发现,第一次必须从 号点开始,而且只有这一次有限制。所以我们可以枚举这个点,即枚举第一次使用的传送器。
接着去想怎么找最多能用多少个传送器。
我们发现,即使求出了每一个传送器的代价,并排了序,也不好直接求从头用能用多少个(从头指的是排完序从代价最少的开始用)。
于是前缀和优化一下, 表示我用了代价最少的 个传送器所需要的代价,即 。
我们现在的问题就转化成了对于一个 ,怎么去找满足 的最大的 。
分析到这了,很容易想到二分了吧。
或者你再看看范围 ,大抵是 ,枚举需要 ,那么我们需要一个 左右的算法,而且还是要在序列上找一个位置,也很容易想到二分吧。
但是我懒得写二分,写了个 。
但是和二分基本是一样的,都还需要考虑怎么把当前枚举的点对 数组的影响排除掉。
假设我们当前枚举到了传送器 。
我们直接 肯定是不行的,因为我们可能会一个传送器算两次,即枚举到 , 已经用过了,但是 时也有可能包含了 。
所以我们先让 减去 (即这个传送器本身的代价与它到 号点的距离之和)再加上 。这个数的含义就是我们去过第 个传送器后,剩下的金币。用这个数 一次,如果包含了我们枚举的数 ,那么我们就可以直接用这个结果作为当前的答案,与最终的答案 取个 ,但是如果没有包含,那么我们用 减去 再 一次作为当前的答案,与最终答案 取 。
最后这一小部分属于代码实现了,建议自己静下来想想。代码实现你不看代码光听我口述,听不明白是正常的,我尽力了。
代码
#include <bits/stdc++.h>
#define int long long
#define M 200005
#define P pair<int, int>
#define MP make_pair
using namespace std;
inline int read() {
int x = 0, s = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
s = -s;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar();
}
return x * s;
}
void write(int x) {
if(x < 0) {
x = ~(x - 1);
putchar('-');
}
if(x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
int n, T, a[M], c, qian[M], ans, cnt;
P pa[M];
signed main() {
T = read();
for(int t = 1; t <= T; ++ t) {
ans = 0;
n = read();
c = read();
for(int i = 1; i <= n; ++ i) {
a[i] = read();
pa[i] = MP(a[i] + min(i, n + 1 - i), a[i] + i);
}
stable_sort(pa + 1, pa + 1 + n);
for(int i = 1; i <= n; ++ i)
qian[i] = pa[i].first + qian[i - 1];
for(int i = 1; i <= n; ++ i) {
if(c < pa[i].second)
continue;
cnt = upper_bound(qian + 1, qian + 1 + n, c - pa[i].second + pa[i].first) - qian - 1;
if(cnt < i)
cnt = upper_bound(qian + 1, qian + 1 + n, c - pa[i].second) - qian;
ans = max(ans, cnt);
}
write(ans);
putchar('\n');
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】