CF187E Heaven Tour
题意
给定 \(n\) 个点,初始在 \(s\) 点,求走遍所有点的最小移动距离,以及方案,需要向左走恰好 \(l\) 次。
\(n \le 10 ^ 5\)。
Sol
难点在于想到枚举终点。
钦定当前若终点在起点右边,那么最优走法就是先向左走到底,然后向右走到底,然后最后再走到终点。
其中中间重复走的段,显然可以发现每一段至多被多走一次,用来多一个 \(l\) 少一个 \(r\),如果一段走了多次,还不如直接重复走旁边的两段。
对于两边本身就走两次的段,尽量全部走 \(l\),这样可以算出来中间需要多走多少次,注意到每次需要的次数是单调不降的,直接对顶堆维护即可。
求方案略显恶心,复杂度:\(O(n \log n)\)。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <queue>
#include <set>
#include <vector>
#define ll long long
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;
#endif
int read() {
int p = 0, flg = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(ll x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
bool _stmer;
const int N = 1e5 + 5;
namespace Hth {
priority_queue <int> q1;
priority_queue <int, vector <int>, greater <int> > q2;
ll ans;
void insert(int x) { q2.push(x); }
int resize(int k) {
while (q1.size() > k)
ans -= q1.top(), q2.push(q1.top()), q1.pop();
while (q1.size() < k && q2.size())
ans += q2.top(), q1.push(q2.top()), q2.pop();
return q1.size() == k;
}
void init() {
while (q1.size()) q1.pop();
while (q2.size()) q2.pop();
ans = 0;
}
} //Hth
array <int, N> s;
vector <ll> solve(int n, int m, int k) {
Hth::init();
ll ans = 0, res = 2e18;
for (int i = k + 1; i <= n; i++) {
ll _res = 2e18;
if (k - 1 + n - i >= m)
_res = 2 * s[n] - s[i] + s[k];
else if (Hth::resize(m - k - n + i + 1))
_res = 2 * s[n] - s[i] + s[k] + 2ll * Hth::ans;
/* if (i == 10) */
/* cerr << m - k - n + i + 1 << " " << Hth::ans << " " << _res << "@@@@" << endl; */
if (_res < res) res = _res, ans = i;
if (i - 1 > k) Hth::insert(s[i] - s[i - 1]);
}
if (!ans) return vector <ll>(1, res);
Hth::init();
for (int i = k + 2; i < ans; i++)
Hth::insert(s[i] - s[i - 1]);
Hth::resize(m - k - n + ans + 1);
/* cerr << m - k - n + ans + 1 << "@" << endl; */
vector <ll> isl; multiset <int> req;
isl.push_back(res);
while (Hth::q1.size())
req.insert(Hth::q1.top()), Hth::q1.pop();
int tp0 = 0;
for (int i = k - 1; i >= 2; i--)
if (m > (k != 1) + (ans != n)) isl.push_back(i), m--, tp0++;
if (k != 1) isl.push_back(1), m--;
for (int i = 2; i <= k - tp0 - 1; i++)
isl.push_back(i);
set <int> tp;
for (int i = k + 1; i < ans - 1; i++)
if (i + 1 != ans && req.find(s[i + 1] - s[i]) != req.end() && m > (ans != n))
tp.insert(i), req.erase(req.find(s[i + 1] - s[i])), m--;
/* for (auto p : tp) */
/* cerr << p << "@" << endl; */
for (int i = k + 1; i <= ans - 1; i++) {
/* if (i + 1 != ans && m > 1 && req.find(s[i + 1] - s[i]) != req.end()) */
/* isl.push_back(i + 1), isl.push_back(i), m--, req.erase(req.find(s[i + 1] - s[i])), i += 2; */
/* else */
/* isl.push_back(i); */
int lst = 0;
while (tp.find(i + lst) != tp.end()) lst++;
if (!lst) isl.push_back(i);
else {
for (int j = lst + i; j >= i; j--)
isl.push_back(j);
i += lst;
/* isl.push_back(-1); */
}
}
for (int i = ans + 1; i <= ans + (n - ans - 1) - (m - (ans != n)); i++)
isl.push_back(i);
if (ans != n) isl.push_back(n);
for (int i = n - 1; i >= n - (m - (ans != n)); i--)
isl.push_back(i);
isl.push_back(ans);
return isl;
}
bool _edmer;
int main() {
cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
int n = read(), m = read(), k = read();
for (int i = 1; i <= n; i++) s[i] = read();
if (m == 0) {
if (k != 1) return puts("-1"), 0;
write(s[n] - s[1]), puts("");
for (int i = 2; i <= n; i++)
write(i), putchar(32);
return puts(""), 0;
}
if (m == n - 1) {
if (k != n) return puts("-1"), 0;
write(s[n] - s[1]), puts("");
for (int i = n - 1; i; i--)
write(i), putchar(32);
return puts(""), 0;
}
vector <ll> tp1 = solve(n, m, k);
m = n - 1 - m, k = n - k + 1;
for (int i = 1; i <= n; i++)
s[i] = s[n] - s[i];
reverse(s.begin() + 1, s.begin() + 1 + n);
/* for (int i = 1; i <= n; i++) */
/* cerr << s[i] << " "; */
/* cerr << endl; */
vector <ll> tp2 = solve(n, m, k);
if (tp1.front() < tp2.front()) {
write(tp1.front()), puts("");
tp1.erase(tp1.begin());
for (auto p : tp1)
write(p), putchar(32);
puts("");
}
else {
write(tp2.front()), puts("");
tp2.erase(tp2.begin());
for (auto p : tp2)
write(n - p + 1), putchar(32);
/* cerr << p << " "; */
puts("");
}
/* cerr << tp.front() << endl; */
/* for (auto k : tp) */
/* cerr << k << " "; */
/* cerr << endl; */
return 0;
}