Loading

NOIP 二十六

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 md

int 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

暴力能优化也要写上,没有可以做的时候就优化暴力。

posted @ 2025-10-21 22:29  qkhm  阅读(5)  评论(0)    收藏  举报