专栏文章
题解:P9292 [ROI 2018] Robomarathon
P9292题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mina701r
- 此快照首次捕获于
- 2025/12/01 23:05 3 个月前
- 此快照最后确认于
- 2025/12/01 23:05 3 个月前
求最优排名是简单的。
假设求 的最优排名,一定只让 先走,,分讨左右拆绝对值,前后扫一遍就可以维护出排名。
假设求 的最优排名,一定只让 先走,,分讨左右拆绝对值,前后扫一遍就可以维护出排名。
考虑求最劣排名。
假设求 的最劣排名。
发现,一定是让一个前后缀的人先走。比如
假设求 的最劣排名。
发现,一定是让一个前后缀的人先走。比如
... a ... b ... x,如果让 先走了,那 的所有点也先走才优,因为这样不仅不会使向 的蔓延时间改变,也让非 的位置先走, 更可能排名靠后。对于下图,
可以发现,对称的 的 的前缀也可以先走,因为蔓延到 的时间不变。
那么 做法就有了。
对于每个 ,枚举 ,让 的人先走。
可以发现,对称的 的 的前缀也可以先走,因为蔓延到 的时间不变。那么 做法就有了。
对于每个 ,枚举 ,让 的人先走。
注意到, 越大越优。假设 内的点的集合是 ,剩下的点的集合是 。
考虑 增加 的变化,从 中取两个点(橙色位置)加入 。
原本 内部点的相对排名不变, 和橙色位置的相对排名不变, 与剩下的 之间的点的相对时间增加 。
发现 增大完全不劣。
于是最优情况只有 种:让 先走、让 先走、让 先走。
前两种容易求出。
第三种,因为 这四种区间, 单增,左右单点分别单调不降,所以可以双指针维护每种区间。
这四种区间分别维护的是 。
CPP
考虑 增加 的变化,从 中取两个点(橙色位置)加入 。原本 内部点的相对排名不变, 和橙色位置的相对排名不变, 与剩下的 之间的点的相对时间增加 。
发现 增大完全不劣。
于是最优情况只有 种:让 先走、让 先走、让 先走。
前两种容易求出。
第三种,因为 这四种区间, 单增,左右单点分别单调不降,所以可以双指针维护每种区间。
这四种区间分别维护的是 。
const int N = 4e5 + 5;
int n, tp, a[N];
int bx[N * 4], bxn;
int Find(int x) {
return lower_bound(bx + 1, bx + bxn + 1, x) - bx;
}
template<int SZ>
struct BIT {
int t[SZ];
void add(int x, int k) {
while (x <= bxn) {
t[x] += k;
x += x & -x;
}
}
int ask(int x) {
int ret = 0;
while (x) {
ret += t[x];
x -= x & -x;
}
return ret;
}
void clr() {
rep(i, 1, bxn)t[i] = 0;
}
};
BIT<N * 4> t2, t3;
namespace Sol1 {
int ans[N];
BIT<N> t1;
void Sol() {
rep(i, 1, n)bx[i] = a[i] - i;
sort(bx + 1, bx + n + 1);
bxn = unique(bx + 1, bx + n + 1) - bx - 1;
rep(i, 1, n) {
int val = Find(a[i] - i);
ans[i] += t1.ask(val - 1);
t1.add(val, 1);
}
t1.clr();
rep(i, 1, n)bx[i] = a[i] + i;
sort(bx + 1, bx + n + 1);
bxn = unique(bx + 1, bx + n + 1) - bx - 1;
per(i, n, 1) {
int val = Find(a[i] + i);
ans[i] += t1.ask(val - 1);
t1.add(val, 1);
}
rep(i, 1, n)printf("%d\n", ans[i] + 1);
}
}
pii b[N];
int ans[N], A[N], B[N], C[N], D[N], res[N];
bool M2;
int main() {
read(n), read(tp);
rep(i, 1, n) read(a[i]);
if (tp == 1) return Sol1::Sol(), 0;
rep(i, 1, n)b[i].fi = a[i] + i - 1, b[i].se = i;
sort(b + 1, b + n + 1);
for (int i = 1, j = 1; i <= n; ++i) {
while (j < i && b[j].fi < b[i].fi) ++j;
ans[b[i].se] = max(ans[b[i].se], j - 1);
}
rep(i, 1, n)b[i].fi = a[i] + n - i, b[i].se = i;
sort(b + 1, b + n + 1);
for (int i = 1, j = 1; i <= n; ++i) {
while (j < i && b[j].fi < b[i].fi)
++j;
ans[b[i].se] = max(ans[b[i].se], j - 1);
}
bxn = 0;
rep(i, 1, n) {
bx[++bxn] = a[i];
bx[++bxn] = a[i] - i;
bx[++bxn] = a[i] + i;
bx[++bxn] = a[i] + min(i - 1, n - i);
}
sort(bx + 1, bx + bxn + 1);
bxn = unique(bx + 1, bx + bxn + 1) - bx - 1;
rep(i, 1, n) {
A[i] = Find(a[i]);
B[i] = Find(a[i] - i);
C[i] = Find(a[i] + i);
D[i] = Find(a[i] + min(i - 1, n - i));
}
for (int i = 2, l = 0, r = n + 1, al, ar; i < n; ++i) {
al = i - min(i - 1, n - i), ar = i + min(i - 1, n - i);
while (l < al) ++l, t2.add(A[l], 1);
while (l > al) t2.add(A[l], -1), --l;
while (r > ar) --r, t2.add(A[r], 1);
while (r < ar) t2.add(A[r], -1), ++r;
res[i] += t2.ask(D[i] - 1);
}
t2.clr();
for (int i = 2, bl, br, al = 2, ar = 1; i < n; ++i) {
bl = al, br = ar;
al = i - min(i - 1, n - i) + 1, ar = i + min(i - 1, n - i) - 1;
while (bl < al) t2.add(C[bl], -1), ++bl;
t2.add(C[i], 1);
while (br < ar) ++br, t3.add(B[br], 1);
t3.add(B[i], -1);
res[i] += t2.ask(C[i] - 1) + t3.ask(B[i] - 1);
ans[i] = max(ans[i], res[i]);
}
rep(i, 1, n)write(ans[i] + 1), pc('\n');
return flush(), 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...