专栏文章
P10068 [CCO 2023] Line Town
P10068题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min3au2b
- 此快照首次捕获于
- 2025/12/01 19:52 3 个月前
- 此快照最后确认于
- 2025/12/01 19:52 3 个月前
这题的特殊性质很有引导性,会了全部特殊性质基本就会正解了。
首先考虑 互不相同怎么做。
发现一个数最后的符号只和它移动距离的奇偶性和原来的符号有关,并且最终序列的绝对值是先递减后递增。
那么自然考虑,按绝对值从大到小,在序列两端填数。设 表示考虑了绝对值 的数,序列左端填了偶数个 / 奇数个数,的最小交换次数。交换次数就是它在原序列中左边或右边(左边还是右边取决于它被填到最左边还是最右边)比它小的数的个数。时间复杂度 ,获得 的高分。
再考虑 怎么做。容易想到枚举最终有 个 换到最左边,但是这样仍然不好直接写出操作次数,因为交换就会变号比较麻烦。
那么有一个处理翻转相邻两位奇偶性的、比较经典的 trick 是翻转奇数位,到这题就是翻转奇数位的符号。这样的好处是操作变成直接交换相邻两个数,不用变号。
现在最终的状态形如 ,其中最后一位是 还是 取决于 的奇偶性。那么我们枚举了 之后,序列中每一个 和 的最终相对位置(在所有 中是从左往右第几个)都能算出来。
那么算交换次数就是 和 的交换次数,加上 内部的交换次数。 和 的交换次数等于一个 左边或右边(左边还是右边取决于它被填到最左边还是最右边) 的个数, 内部的交换次数就是每个 原来的相对位置减去最终的相对位置绝对值之和。
那么做到这一步其实可以发现正解就是上面两个做法拼起来。仍然是按 从大到小 DP,设当前考虑的绝对值是 ,把 看成 , 看成 ,绝对值 的数看成 ,然后套用 的做法即可。
实现时要特别小心奇偶性的处理。
最终总时间复杂度 ,但是除了离散化和计算每个数左边(和右边)比它小的数的个数时间复杂度是 之外,其他的部分都是 的。
代码
CPP// Problem: P10068 [CCO 2023] Line Town
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P10068
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#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;
using ll = long long;
using ull = unsigned long long;
using db = double;
using ldb = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
namespace IO {
const int maxn = 1 << 20;
char ibuf[maxn], *iS, *iT, obuf[maxn], *oS = obuf;
inline char gc() {
return (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++) : *iS++);
}
template<typename T = int>
inline T read() {
char c = gc();
T x = 0;
bool f = 0;
while (c < '0' || c > '9') {
f |= (c == '-');
c = gc();
}
while (c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = gc();
}
return f ? ~(x - 1) : x;
}
inline int reads(char *s) {
char c = gc();
int len = 0;
while (isspace(c)) {
c = gc();
}
while (!isspace(c) && c != -1) {
s[len++] = c;
c = gc();
}
s[len] = '\0';
return len;
}
inline string reads() {
char c = gc();
string s;
while (isspace(c)) {
c = gc();
}
while (!isspace(c) && c != -1) {
s += c;
c = gc();
}
return s;
}
inline void flush() {
fwrite(obuf, 1, oS - obuf, stdout);
oS = obuf;
}
struct Flusher {
~Flusher() {
flush();
}
} AutoFlush;
inline void pc(char ch) {
if (oS == obuf + maxn) {
flush();
}
*oS++ = ch;
}
inline void write(char *s) {
for (int i = 0; s[i]; ++i) {
pc(s[i]);
}
}
inline void write(const char *s) {
for (int i = 0; s[i]; ++i) {
pc(s[i]);
}
}
template<typename T>
inline void write(T x) {
static char stk[64], *tp = stk;
if (x < 0) {
x = ~(x - 1);
pc('-');
}
do {
*tp++ = x % 10;
x /= 10;
} while (x);
while (tp != stk) {
pc((*--tp) | 48);
}
}
template<typename T>
inline void writesp(T x) {
write(x);
pc(' ');
}
template<typename T>
inline void writeln(T x) {
write(x);
pc('\n');
}
}
using IO::read;
using IO::reads;
using IO::write;
using IO::pc;
using IO::writesp;
using IO::writeln;
const int maxn = 500100;
const ll inf = 0x3f3f3f3f3f3f3f3fLL;
int n, a[maxn], lsh[maxn], tot, ls[maxn], rs[maxn], b[maxn], c[maxn], d[maxn];
ll f1[maxn], f2[maxn], f3[maxn], f4[maxn], pre[2][maxn], suf[2][maxn];
bool vis[maxn];
vector<int> ap[maxn];
namespace BIT {
int c[maxn];
inline void update(int x, int d) {
for (int i = x; i <= tot; i += (i & (-i))) {
c[i] += d;
}
}
inline int query(int x) {
int res = 0;
for (int i = x; i; i -= (i & (-i))) {
res += c[i];
}
return res;
}
}
void solve() {
n = read();
for (int i = 1; i <= n; ++i) {
a[i] = read();
if (a[i] < 0) {
a[i] = -a[i];
vis[i] = 1;
}
lsh[++tot] = a[i];
}
sort(lsh + 1, lsh + tot + 1);
tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
for (int i = 1; i <= n; ++i) {
a[i] = lower_bound(lsh + 1, lsh + tot + 1, a[i]) - lsh;
++b[a[i]];
}
for (int i = 1; i <= tot; ++i) {
b[i] += b[i - 1];
}
for (int i = 1; i <= n; ++i) {
ls[i] = BIT::query(a[i] - 1);
rs[i] = b[a[i] - 1] - ls[i];
BIT::update(a[i], 1);
}
mems(b, 0);
for (int i = 1; i <= n; ++i) {
if (vis[i] ^ (i & 1)) {
a[i] = -a[i];
}
ap[abs(a[i])].pb(i);
}
ll f[2] = {0, inf};
int r = n;
for (int k = tot; k; --k) {
if (lsh[k] == 0) {
break;
}
ll g[2] = {inf, inf};
int m1 = 0, m2 = 0, cnt = 0;
for (int i : ap[k]) {
++cnt;
if (a[i] > 0) {
b[++m1] = i;
d[i] = cnt;
} else {
c[++m2] = i;
d[i] = cnt;
}
}
for (int i = 1; i <= m1; ++i) {
f1[i] = f1[i - 1] + ls[b[i]];
f2[i] = f2[i - 1] + rs[b[i]];
b[i] = d[b[i]];
}
for (int i = 1; i <= m2; ++i) {
f3[i] = f3[i - 1] + ls[c[i]];
f4[i] = f4[i - 1] + rs[c[i]];
c[i] = d[c[i]];
}
for (int j = 0; j <= 1; ++j) {
for (int i = 1, p1 = 1, p2 = 1; i <= m1 + m2; ++i) {
pre[j][i] = pre[j][i - 1];
if ((j ^ i) & 1) {
pre[j][i] += abs(b[p1++] - i);
} else {
pre[j][i] += abs(c[p2++] - i);
}
}
}
suf[0][m1 + m2 + 1] = suf[1][m1 + m2 + 1] = 0;
for (int j = 0; j <= 1; ++j) {
for (int i = m1 + m2, o = (r & 1) ^ j, p1 = m1, p2 = m2; i; --i, o ^= 1) {
suf[j][i] = suf[j][i + 1];
if (o) {
suf[j][i] += abs(c[p2--] - i);
} else {
suf[j][i] += abs(b[p1--] - i);
}
}
}
for (int j = 0; j <= 1; ++j) {
for (int i = 0; i <= m1 + m2; ++i) {
int x = (i + 1) >> 1, y = (i >> 1);
if (j) {
swap(x, y);
}
int rx = m1 - x, ry = m2 - y;
if (rx < 0 || ry < 0) {
continue;
}
if ((r ^ j) & 1) {
if (rx != ry && rx + 1 != ry) {
continue;
}
} else {
if (rx != ry && rx != ry + 1) {
continue;
}
}
g[(i & 1) ^ j] = min(g[(i & 1) ^ j], f[j] + ((((f1[x] + f3[y] + f2[m1] - f2[x] + f4[m2] - f4[y]) << 1) + pre[j][i] + suf[j][i + 1]) >> 1));
}
}
f[0] = g[0];
f[1] = g[1];
r -= (int)ap[k].size();
}
writeln(min(f[0], f[1]) > 1e18 ? -1 : min(f[0], f[1]));
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...