G2. Teleporters (Hard Version)
G2. Teleporters (Hard Version)
The only difference between the easy and hard versions are the locations you can teleport to.
Consider the points on the number line. There is a teleporter located on each of the points . At point , you can do the following:
- Move left one unit: it costs coin.
- Move right one unit: it costs coin.
- Use a teleporter at point , if it exists: it costs coins. As a result, you can choose whether to teleport to point or point . Once you use a teleporter, you can't use it again.
You have coins, and you start at point . What's the most number of teleporters you can use?
Input
The input consists of multiple test cases. The first line contains an integer () — the number of test cases. The descriptions of the test cases follow.
The first line of each test case contains two integers and (; ) — the length of the array and the number of coins you have respectively.
The following line contains space-separated positive integers () — the costs to use the teleporters.
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, output the maximum number of teleporters you can use.
Example
input
10 5 6 1 1 1 1 1 8 32 100 52 13 6 9 4 100 35 1 1 5 4 5 4 3 2 1 5 9 2 3 1 4 1 5 8 2 3 1 4 1 4 3 2 3 4 1 4 9 5 4 3 3 2 14 7 5 5 600000000 500000000 400000000 300000000 200000000 100000000
output
2 3 0 1 3 2 1 1 2 2
Note
In the first test case, you can move one unit to the right, use the teleporter at index and teleport to point , move one unit to the left and use the teleporter at index . You are left with coins, and wherever you teleport, you won't have enough coins to use another teleporter. You have used two teleporters, so the answer is two.
In the second test case, you go four units to the right and use the teleporter to go to , then go three units left and use the teleporter at index to go to , and finally, you go left four times and use the teleporter. The total cost will be , and you used three teleporters.
In the third test case, you don't have enough coins to use any teleporter, so the answer is zero.
解题思路
与G1. Teleporters (Easy Version)不同,当使用了某个传送器后不仅可以选择传送到下标处,还可以传送到下标处。
很明显,如果当前在的某个位置(也就是不是起点),每个传送器的代价为,因此为了取到最大数目的传送器就应该按照代价从小到大来选择传送器。
问题是现在是从点开始,因此会有贪心的思路是从中选择最小的所对应的下标,然后从走到,再按照上面的做法来选择传送器。但这种做法是有问题的,参考下面的数据:
2 14 7 5
按照上面贪心的思路,,当从走到后还剩下,已经选不了下标处的传送器了。实际上应该取,然后再传送到处,这样总代价就是,最多可以选择个传送器。
因此贪心是行不通的,那么就直接枚举第一次走到的下标,此时还剩下,为了快速求出最多还能选择多少个传送器,我们按照之前的思路求出每个传送器的最小代价,然后从小到大排序,再求前缀和,那么就可以二分出来不超过的最大值了。剩下的细节见注释。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 typedef pair<int, int> PII; 6 7 const int N = 2e5 + 10; 8 9 PII a[N]; 10 LL s[N]; 11 12 void solve() { 13 int n, m; 14 scanf("%d %d", &n, &m); 15 for (int i = 1; i <= n; i++) { 16 int x; 17 scanf("%d", &x); 18 a[i] = {x + min(i, n + 1 - i), x + i}; 19 } 20 sort(a + 1, a + n + 1); 21 for (int i = 1; i <= n; i++) { 22 s[i] = s[i - 1] + a[i].first; 23 } 24 int ret = 0; 25 for (int i = 1; i <= n; i++) { // 枚举第一次到达的下标 26 if (a[i].second <= m) { // 至少可以选择这个传送器 27 int l = 0, r = n; // 左端点从0开始,如果最后有l=0意味着不能选择第二个传传送器 28 while (l < r) { 29 int mid = l + r + 1 >> 1; 30 LL t = s[mid] + a[i].second; // 总代价 31 if (i <= mid) t -= a[i].first; // 选择的传送器包括了i,应该删除对于的数据 32 if (t <= m) l = mid; 33 else r = mid - 1; 34 } 35 ret = max(ret, l + (l < i)); // 如果l<i那么就需要额外加上i这个位置的传送器 36 } 37 } 38 printf("%d\n", ret); 39 } 40 41 int main() { 42 int t; 43 scanf("%d", &t); 44 while (t--) { 45 solve(); 46 } 47 48 return 0; 49 }
参考资料
Codeforces Round #849 (Div. 4) Editorial:https://codeforces.com/blog/entry/112282
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17092492.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效