# Codeforces 1791 G2. Teleporters (Hard Version)
###### tags: `codeforces` `binary search`
[題目連結](https://codeforces.com/contest/1791/my)
# Method Sort + Binary search
:::info
:bulb: **Concept**:
1. 將從兩邊出發的coin 由小至大排序, 只要coin總和 小於等於 初始 coin即可.
case 1: 前面所選的位置包含從左邊出發的位置
直接計算數量回傳即可
case 2: 前面所選的位置**不包含**從左邊出發的位置
表示全部都是從右邊出發.
採用binary search的作法
2. binary search 作法
從case 2可以得知付出最少coin都是從右邊出發的,
但是題目要求第一次必須從左邊出發,
因此我們透過對右邊出發所需要的coin做排序,
然後每次假設從 左邊 index 0 ~ n-1 出發,
透過binary search 搜尋 從右邊出發還可以獲得多少個位置.
:::
TC: O(NlogN) SC: O(N)
完整程式碼
```cpp=
#include <bits/stdc++.h>
#include <unordered_set>
#include <unordered_map>
#include <chrono>
#include <iostream>
#include <string>
using namespace std;
typedef long long int ll;
const int mod = 998244353;
#define INF 1e9
#define CLR(a) memset(a, 0, sizeof(a))
#define SET(a, val) memset(a, val, sizeof(a))
#define N 200005
ll nums[N];
pair<ll, int> left_nums[N];
pair<ll, int> right_nums[N];
ll sum_nums[N];
bool visited[N];
int binary_search(int i, ll n, ll c)
{
int idx = right_nums[i].second;
int l = 0;
int r = n - 1;
if (c < (nums[idx] + idx + 1)) {
return 0;
}
c -= (nums[idx] + idx + 1);
while (l < r) {
int m = r - (r - l) / 2;
ll dup = (m > i) ? right_nums[i].first : 0;
if (c >= (sum_nums[m] - dup)) {
l = m;
}
else {
r = m - 1;
}
}
return l + (i >= l);
}
int do1(ll n, ll c)
{
int lidx = 0;
int ridx = 0;
bool used_left = false;
int output = 0;
for (int i = 1; (i <= n); i++) {
while (visited[left_nums[lidx].second]) {
lidx++;
}
while (visited[right_nums[ridx].second]) {
ridx++;
}
if (c < min(left_nums[lidx].first, right_nums[ridx].first)) {
break;
}
if (left_nums[lidx] <= right_nums[ridx]) {
c -= left_nums[lidx].first;
visited[left_nums[lidx].second] = true;
lidx++;
used_left = true;
}
else {
c -= right_nums[ridx].first;
visited[right_nums[ridx].second] = true;
ridx++;
}
output++;
}
return used_left ? output : 0;
}
void solve(int round)
{
ll n, c, cur_c;
int output = 0;
CLR(nums);
CLR(visited);
CLR(left_nums);
CLR(right_nums);
CLR(sum_nums);
cin >> n >> c;
for (int i = 0; i < n; i++) {
cin >> nums[i];
left_nums[i] = { nums[i] + i + 1, i };
right_nums[i] = { nums[i] + n - i, i };
}
sort(left_nums, left_nums + n);
sort(right_nums, right_nums + n);
output = do1(n, c);
if (output > 0) {
printf("%d\n", output);
return;
}
for (int i = 0; i < n; i++) {
sum_nums[i + 1] = sum_nums[i] + right_nums[i].first;
}
for (int i = 0; i < n; i++) {
output = max(output, binary_search(i, n, c));
}
printf("%d\n", output);
}
```