Little Q \text{Little Q} Little Q is playing an RPG \text{RPG} RPG online game. In this game, there are n n n characters labeled by 1 , 2 , … , n 1,2,…,n 1,2,…,n. The i-th character has three types of quotas:
You are the team leader working for the new balance between these n n n characters, aiming at bringing hope to the weak characters. For each character, your teammates have made a plan to strengthen some skills such that the three quotas may be increased as a result. Note that it is not allowed to weaken characters, because it will make their owners upset.
To make a perfect balance, you need to accept some plans and deny others such that the gap between all the n n n characters is minimized. Note that a plan can only be entirely accepted or entirely denied. Here, the gap is defined as:
max ( max 1 ≤ i ≤ n a i − min 1 ≤ i ≤ n a i , max 1 ≤ i ≤ n b i − min 1 ≤ i ≤ n b , max 1 ≤ i ≤ n c i − min 1 ≤ i ≤ n c i ) \max (\max\limits_{1\leq i\leq n}a_i-\min\limits_{1\leq i\leq n} a_i,\max\limits_{1\leq i\leq n}b_i-\min\limits_{1\leq i\leq n} b,\max\limits_{1\leq i\leq n}c_i-\min\limits_{1\leq i\leq n} c_i) max(1≤i≤nmaxai−1≤i≤nminai,1≤i≤nmaxbi−1≤i≤nminb,1≤i≤nmaxci−1≤i≤nminci)
小 Q \text{Q} Q 正在玩一款 RPG \text{RPG} RPG(开放世界游戏)。
在这个游戏中,有 n n n 个角色被标记为 1 , 2 , ⋯ , n 1,2,\cdots,n 1,2,⋯,n。第 i i i 个角色有三种配额类型:
a i a_i ai -他在15秒内所能达到的最大伤害。
b i b i bi -他在40秒内所能达到的最大伤害。
c i c i ci -他在120秒内所能达到的最大伤害。
你是(万恶)善良的策划,为这 n n n 个角色之间的新平衡而努力,旨在为弱势角色带来希望。对于每个角色,你的队友已经制定了一个计划来加强一些技能,这样三个配额可能会因此而增加。
注意,它不允许削弱角色,因为它会使他们的主人心烦意乱。
为了达到完美的平衡,你需要接受一些计划并拒绝其他计划,这样所有 n n n 个角色之间的差距就会最小化。
请注意,计划只能被完全接受或完全拒绝。
这里,差距定义为
max ( max 1 ≤ i ≤ n a i − min 1 ≤ i ≤ n a i , max 1 ≤ i ≤ n b i − min 1 ≤ i ≤ n b , max 1 ≤ i ≤ n c i − min 1 ≤ i ≤ n c i ) \max (\max\limits_{1\leq i\leq n}a_i-\min\limits_{1\leq i\leq n} a_i,\max\limits_{1\leq i\leq n}b_i-\min\limits_{1\leq i\leq n} b,\max\limits_{1\leq i\leq n}c_i-\min\limits_{1\leq i\leq n} c_i) max(1≤i≤nmaxai−1≤i≤nminai,1≤i≤nmaxbi−1≤i≤nminb,1≤i≤nmaxci−1≤i≤nminci)
一眼 2-SAT \text{2-SAT} 2-SAT。(很明显,我不会)
难点在建图,我们发现对于这道题不是很好建图,于是我们曲线救国。
我们可以先二分答案,然后在判断二分的答案能否满足。
这时候我们建边就可以按如下方法建边:
然后就是一个 2 − S A T 2-SAT 2−SAT 版题了。
#include
using namespace std;
int T, n, a[200005][5], ans, k, mid, cnt, tot, vis[200005], q[200005], f[200005];
struct node {
int id[200005], h, t, d;
int get(int val) {
if (h <= t)
if (a[id[h]][d] < val - mid) {
h++;
return id[h - 1];
}
if (h <= t)
if (a[id[t]][d] > val + mid) {
t--;
return id[t + 1];
}
return 0;
}
} A[5];
bool cmp(int x, int y) { return a[x][k] < a[y][k]; }
void dfs(int x) {
if (vis[x])
return;
vis[x] = 1;
for (int i = 1; i <= 3; i++)
while (1) {
int to = A[i].get(a[x][i]);
if (!to)
break;
dfs(to <= n ? to + n : to - n);
}
q[++tot] = x;
}
void ddfs(int x) {
if (!vis[x])
return;
vis[x] = 0, f[x] = cnt;
for (int i = 1; i <= 3; i++)
while (1) {
int to = A[i].get(a[x <= n ? x + n : x - n][i]);
if (!to)
break;
ddfs(to);
}
}
bool check() {
cnt = tot = 0;
for (int i = 1; i <= n * 2; i++) vis[i] = 0;
for (int i = 1; i <= 3; i++) A[i].h = 1, A[i].t = n * 2;
for (int i = 1; i <= n * 2; i++)
if (!vis[i])
dfs(i);
for (int i = 1; i <= 3; i++) A[i].h = 1, A[i].t = n * 2;
for (int i = tot; i; i--)
if (vis[q[i]])
cnt++, ddfs(q[i]);
for (int i = 1; i <= n; i++)
if (f[i] == f[i + n])
return 0;
return 1;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d%d%d%d%d", &a[i][1], &a[i][2], &a[i][3], &a[i + n][1], &a[i + n][2], &a[i + n][3]);
int minn = 1e9, maxn = -1e9;
for (int i = 1; i <= n * 2; i++)
for (int j = 1; j <= 3; j++) maxn = max(maxn, a[i][j]), minn = min(minn, a[i][j]);
for (k = 1; k <= 3; k++) {
for (int i = 1; i <= n * 2; i++) A[k].id[i] = i;
A[k].h = 1, A[k].t = n * 2, A[k].d = k;
sort(A[k].id + 1, A[k].id + n * 2 + 1, cmp);
}
int l = 0, r = maxn - minn;
while (l <= r) {
mid = (l + r) / 2;
if (check())
ans = mid, r = mid - 1;
else
l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}