A.
圆心处向周围连边就将整个圆分成了若干个不相关的部分。
断环成链,记 \(f[l, r]\) 为 \([l, r]\) 内连通的最小代价,转移考虑是否选择 \((l, r)\) 这条边。
枚举分界点转移。
注意当目前区间大于半圆的时候不能选择这条边。
因为这样会让圆心无法连边。
接下来证明:圆心至多只会连出两条边。
将圆心相对高度看作 \(0\) ,则如果有两个相邻的正/负数,则两个正/负数之间连边才更优。
然后就只可能是正负交替:
调整成红色边代价不变。
同时发现,如果有两条出边,则这两个点一定一个比圆心高,另一个比圆心低。
使用线段树+预处理,做到单次询问 \(\mathcal O(\log V + n)\) 。
点击查看代码
#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = (a), ed##i = (b); i <= ed##i; ++i)
#define rep(i, a, b) for (int i = (a), ed##i = (b); i >= ed##i; --i)
#define il inline
#define arr(ty, tn) std::array<ty, tn>
#define gmx(a, b) a = std::max(a, b)
#define gmn(a, b) a = std::min(a, b)template <typename T>
void _debug(const T& t) { std::cerr << t << '\n'; }
template <typename T, typename... Args>
void _debug(const T& t, const Args&...res) { std::cerr << t << ' '; _debug(res...); }
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)const int LN = 2000 + 7;
const int V = 1e9;
typedef long long ll;
typedef std::pair<int, int> PII;bool FIRPOS;const ll inf = 1e16;
int C, n, q; arr(int, 2) a[LN]; ll f[LN][LN], g[LN];
ll mn[LN << 10], tg[LN << 10]; int ls[LN << 10], rs[LN << 10], tot, rt;bool ENDPOS;il ll ABS(ll x) { return x < 0 ? -x : x; }
#define md ((s + t) >> 1)
il void pu(int p) { mn[p] = std::min(std::min(mn[ls[p]], mn[rs[p]]), tg[p]); }
void mdy(int&p, int l, int r, ll v, int s = 0, int t = V) {if (r < s or t < l) return; if (!p) p = ++tot, mn[p] = tg[p] = inf;if (l <= s and t <= r) return gmn(tg[p], v), pu(p);mdy(ls[p], l, r, v, s, md), mdy(rs[p], l, r, v, md + 1, t), pu(p);
}
ll qry(int p, int d, int s = 0, int t = V) {if (!p) return inf; if (s == t) return mn[p];return std::min(tg[p], d <= md ? qry(ls[p], d, s, md) : qry(rs[p], d, md + 1, t));
}
#undef mdint main() {std::ios::sync_with_stdio(false),std::cin.tie(nullptr), std::cout.tie(nullptr);int c1 = clock();std::cin >> C >> n >> q; mn[0] = inf;lep(i, 1, n) std::cin >> a[i][0];lep(i, 1, n) std::cin >> a[i][1];std::sort(a + 1, a + 1 + n);lep(i, 1, n) a[i + n] = { a[i][0] + C, a[i][1] };int r;lep(len, 2, n) {lep(l, 1, n * 2 - len + 1) { r = l + len - 1, f[l][r] = inf;lep(i, l + 1, r - 1) gmn(f[l][r], f[l][i] + f[i][r]);if (a[r][0] - a[l][0] <= C / 2)lep(i, l, r - 1) gmn(f[l][r], f[l][i] + f[i + 1][r] + ABS(a[l][1] - a[r][1]));}}lep(i, 1, n) { g[i] = inf;lep(j, i, i + n - 1) gmn(g[i], f[i][j] + f[j + 1][i + n]);}lep(i, 1, n) lep(j, i + 1, n) { ll t1 = inf, t2 = inf;lep(k, i, j - 1) gmn(t1, f[i][k] + f[k + 1][j]);lep(p, j, i + n - 1) gmn(t2, f[j][p] + f[p + 1][i + n]);int l = std::min(a[i][1], a[j][1]), r = std::max(a[i][1], a[j][1]);mdy(rt, l, r, t1 + t2 + r - l);}ll ans;while (q--) { std::cin >> r, ans = qry(rt, r);lep(i, 1, n) gmn(ans, g[i] + ABS(r - a[i][1]));std::cout << ans << ' ';}std::cout << '\n';std::cerr << clock() - c1 << " ms " << std::fabs(&ENDPOS - &FIRPOS) / 1024 / 1024 << " MB\n";return 0;
}
Tips
暴力能优化也要写上,没有可以做的时候就优化暴力。