AtCoder Regular Contest 170 D Triangle Card Game
赛后调了 40min,哈哈。
首先先把 \(a, b\) 排序。
考虑先枚举 Alice 选的数 \(a_i\),然后若 \(\forall j, \exists k \ne i, (a_i, b_j, a_k)\) 能组成三角形,Alice 就赢了。
考虑简化条件。\((x, y, z)\) 能形成三角形的充要条件是 \(z \in (|x - y|, x + y)\)。那么条件变为 \(\forall j, \exists k \ne i, a_k \in (|b_j - a_i|, b_j + a_i)\)。
看到有个绝对值,考虑分类讨论。若 \(b_j \le a_i\),那么 \(a_k \in (a_i - b_j, a_i + b_j)\)。可以发现 \(b_j\) 越小这个范围越窄。所以只用判断 \(b_j\) 最小,即 \(j = 1\) 的情况。这个可以维护一个 multiset,然后 upper_bound 找大于 \(a_i - b_1\) 的最小数判断。
考虑 \(b_j > a_i\)。考虑对每个 \(i\) 求出一个分界点 \(p_i\) 使得 \(b_{p_i}\) 为第一个大于 \(a_i\) 的数。那么条件变为 \(\forall j \ge p_i, \exists k \ne i, a_k \in (b_j - a_i, b_j + a_i)\)。
变形一下可得 \(b_j \in (a_k - a_i, a_k + a_i)\)。
这个条件就比较有意思了。可以把它看成是一个中点为 \(a_k\),长度为 \(2a_i\) 的线段。考虑把所有 \(a, b\) 排列在数轴上,设 \(b_j\) 夹在 \(a_x, a_{x + 1}\) 之间。那么当 \(a_i \le t = \min(b_j - a_x, a_{x + 1} - b_j)\) 时,\(b_j\) 是不能被覆盖的。所以对于一个 \(i\),若 \(i \le q_j\) 且 \(j \ge p_i\),\(i\) 就不满足条件,就不能让 Alice 赢。这是一个二维偏序的形式,考虑第一维扫描线,第二维树状数组维护即可。
然后你写出来这个东西发现被这个 case 卡掉了:
1
2
3 8
4 4
答案是 Bob,而你输出了 Alice。原因是我们没有考虑 Alice 不能选重复的数的情况。考虑若 \(q_j = x\) 就会出现选重复数的情况,若 \(a_{x + 1}\) 不能用长度为 \(2a_x\) 的线段覆盖到 \(b_j\),即 \(a_x + b_i \le a_{x + 1}\),就让 \(q_j \gets q_j + 1\)。
总时间复杂度为 \(O(n \log n)\)。
code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 200100;
ll n, a[maxn], b[maxn];
vector<int> vc[maxn];
namespace BIT {
int c[maxn];
inline void init() {
for (int i = 0; i <= n; ++i) {
c[i] = 0;
}
}
inline void update(int x, int d) {
for (int i = x; i; i -= (i & (-i))) {
c[i] += d;
}
}
inline int query(int x) {
int res = 0;
for (int i = x; i <= n; i += (i & (-i))) {
res += c[i];
}
return res;
}
}
void solve() {
scanf("%lld", &n);
multiset<ll> S;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
S.insert(a[i]);
vector<int>().swap(vc[i]);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld", &b[i]);
}
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
int m = unique(b + 1, b + n + 1) - b - 1;
BIT::init();
a[n + 1] = 1e18;
a[0] = -1e18;
for (int i = 1; i <= m; ++i) {
int p = lower_bound(a + 1, a + n + 1, b[i]) - a;
ll t = min(a[p] - b[i], b[i] - a[p - 1]);
int q = upper_bound(a + 1, a + n + 1, t) - a;
if (q + 1 == p && a[q] + b[i] <= a[q + 1]) {
++q;
}
if (q <= n) {
// printf("%d %d\n", q, i);
// printf("t: %lld %d %lld %lld\n", t, p, a[p - 1], b[i]);
vc[q].pb(i);
}
BIT::update(i, 1);
}
for (int i = 1; i <= n; ++i) {
for (int j : vc[i]) {
BIT::update(j, -1);
}
S.erase(S.find(a[i]));
int p = upper_bound(b + 1, b + m + 1, a[i]) - b;
auto it = S.upper_bound(abs(a[i] - b[1]));
if ((a[i] < b[1] || it != S.end() && *it < a[i] + b[1]) && !BIT::query(p)) {
// printf("i: %d\n", i);
puts("Alice");
return;
}
S.insert(a[i]);
}
puts("Bob");
}
int main() {
// freopen("D.in", "r", stdin);
// freopen("my.out", "w", stdout);
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号