[CF1260D] A Game with Traps
首先,假设带 \(p\) 个人可以,那么带更少的人一定可以。
那么,可以二分带多少个人。
设当前二分带 \(x\) 个人。
带敏捷值最大的 \(x\) 个士兵肯定最好。
先去除当前无用的陷阱,即 \(d_i\) 小于等于 \(x\) 个士兵中的最小敏捷值。
陷阱区间不相交时
然后就是自己从 \(l_i\) 走到 \(r_i\) 解除这个陷阱,再走回来
陷阱区间相交时
看一看下面这个。

肯定不会从一个一个地从每个区间左边走到右边。
而是从第一个区间左边一直走到第二个区间右边。
写的时候直接左右端点差分,加贡献时对 \(2\) 取个 \(\min\)(往返总共走 \(2\) 次)。
#include <bits/stdc++.h>
#define int long long
#define mid (l + r >> 1)
using namespace std;
inline int read()
{
int f = 0, ans = 0;
char c = getchar();
while (!isdigit(c))
f |= c == '-', c = getchar();
while (isdigit(c))
ans = (ans << 3) + (ans << 1) + c - 48, c = getchar();
return f ? -ans : ans;
}
void write(int x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
constexpr int N = 2e5 + 5, inf = 1e18;
int m, n, k, t, a[N];
int adj[N];
struct trap
{
int l, r, d;
} b[N];
inline bool check(int x)
{
int mn = a[x], ti = n + 1;
for (int i = 1; i <= k; ++i)
if (mn < b[i].d)
adj[b[i].l] += 2, adj[b[i].r + 1] -= 2;
for (int i = 1; i <= n; ++i)
adj[i] += adj[i - 1], ti += min(adj[i], 2ll);
for (int i = 1; i <= n; ++i)
adj[i] = 0;
return ti <= t;
}
signed main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
m = read(), n = read(), k = read(), t = read();
for (int i = 1; i <= m; ++i)
a[i] = read();
sort(a + 1, a + m + 1, greater<>());
a[0] = inf;
for (int i = 1; i <= k; ++i)
b[i].l = read(), b[i].r = read(), b[i].d = read();
int l = 0, r = m, it = -1;
while (l <= r)
check(mid)
? (it = mid, l = mid + 1)
: (r = mid - 1);
write(it);
return 0;
}

浙公网安备 33010602011771号