Educational Codeforces Round 171 (Rated for Div. 2) 題解

definieren發表於2024-11-03

A. Perpendicular Segments

顯然構造一個 \(k \times k\) 的左下角是原點的正方形即可。

void slv() {
	int x, y, k; Read(x, y, k);
	int mn = min(x, y);
	if (mn * mn * 2 >= k * k)
		Write(0, ' ', 0, ' ', mn, ' ', mn, '\n'),
		Write(0, ' ', mn, ' ', mn, ' ', 0, '\n');
	return;
}

B. Black Cells

偶數的情況一定是相鄰兩兩匹配,奇數時可以空出來一個。

預處理前字尾 min 即可。

constexpr int N = 2e3 + 5;
int n;
ll a[N], pre[N], suf[N];

void slv() {
	Read(n);
	for (int i = 1; i <= n; i ++) a[i] = Read<ll>();
	if (n == 1) { Puts("1"); return; }
	if (n & 1) {
		for (int i = 2; i <= n; i += 2)
			pre[i] = max(pre[i - 2], a[i] - a[i - 1]);
		for (int i = n - 1; i >= 1; i -= 2)
			suf[i] = max(suf[i + 2], a[i + 1] - a[i]);
		ll ans = 1e18;
		for (int i = 2; i <= n + 1; i += 2)
			cmin(ans, max(suf[i], pre[i - 2]));
		Write(ans, '\n');
	} else {
		ll ans = 0;
		for (int i = 2; i <= n; i += 2)
			cmax(ans, a[i] - a[i - 1]);
		Write(ans, '\n');
	}
	return;
}

C. Action Figures

一定是讓後面的 1 儘量免費,所以從後往前貪即可。

constexpr int N = 4e5 + 5;
int n;
char s[N];
bool vis[N], mrk[N];

void slv() {
	Read(n), Read(s + 1);
	ll ans = 0; int j = n, o = 0;
	for (int i = n; i >= 1; i --) {
		if (s[i] == '1' && !vis[i]) {
			if (!o) {
				while (j >= i) j --;
				while (j >= 1 && (s[j] == '1' || vis[j])) j --;
				if (j) mrk[i] = true, vis[j] = true, j --;
				else o = 1, j = 1;
			}
			if (o) {
				while (j < i && vis[j]) j ++;
				if (j < i && !vis[j]) vis[j] = true, mrk[i] = true;
			}
		}
	}
	for (int i = 1; i <= n; i ++)
		if (!mrk[i]) ans += i;
	Write(ans, '\n');
	return;
}

D. Sums of Segments

按長度為 \(1, 2, \cdots, n\) 分塊,定位 \(l\)\(r\) 所在的塊可以 lower_bound。

將詢問差分成 \([1, r] - [1, l)\)

對於整塊的貢獻可以直接字首和預處理。

散塊的貢獻可以透過維護 \(a_i \cdot i\) 的字首和來實現快速查詢。

constexpr int N = 3e5 + 5;
int n, q, a[N];
ll cnt[N], sum[N], prod[N], sigm[N];

void slv() {
	Read(n);
	for (int i = 1; i <= n; i ++) Read(a[i]), cnt[i] = n - i + 1;
	partial_sum(cnt + 1, cnt + n + 1, cnt + 1);
	for (int i = n; i >= 1; i --)
		sum[i] = sum[i + 1] + 1ll * a[i] * (n - i + 1);
	for (int i = 1; i <= n; i ++) sum[i] += sum[i - 1];
	for (int i = 1; i <= n; i ++)
		prod[i] = prod[i - 1] + i * a[i];
	for (int i = 1; i <= n; i ++)
		sigm[i] = sigm[i - 1] + a[i];
	Read(q);
	auto calc = [&](int l, int L, int R) {
		ll ans = (sigm[L - 1] - sigm[l - 1]) * (R - L + 1);
		return ans + (R + 1) * (sigm[R] - sigm[L - 1])
							- (prod[R] - prod[L - 1]);
	};
	while (q --) {
		ll l, r; Read(l, r);
		int posl = lower_bound(cnt + 1, cnt + n + 1, l) - cnt;
		int posr = lower_bound(cnt + 1, cnt + n + 1, r) - cnt;
		ll ans = 0;
		l = l - cnt[posl - 1] + posl - 1;
		r = r - cnt[posr - 1] + posr - 1;
		if (posl < posr) ans += sum[posr - 1] - sum[posl];
		if (posl == posr) ans += calc(posl, l, r);
		else ans += calc(posl, l, n) + calc(posr, posr, r);
		Write(ans, '\n');
	}
	return;
}

E. Best Subsequence

看成選一個數有 1 的貢獻,選一個二進位制位有 1 的代價,選一個數就一定要選它對應的二進位制位。

這樣就轉化成了最大權閉合子圖,直接流。

void slv() {
	static constexpr int INF = 1e9;
	int n; Read(n);
	MaxFlow_Graph<int> G(n + 60 + 2);
	int S = n + 60, T = S + 1;
	for (int i = 0; i < n; i ++) G.Add_Edge(S, i, 1);
	for (int i = 0; i < 60; i ++) G.Add_Edge(n + i, T, 1);
	for (int i = 0; i < n; i ++) {
		ll x; Read(x);
		for (int j = 0; j < 60; j ++)
			if (x >> j & 1) G.Add_Edge(i, j + n, INF);
	}
	Write(n - G.Max_Flow(S, T), '\n');
	return;
}

F. Bermart Ice Cream

先考慮如果只有一家商店怎麼做。

問題變成了維護一個物品序列,支援 push back、pop front、求揹包。

這個可以透過用棧模擬 queue 來完成。

對於原問題,可以離線建操作樹,然後在操作樹上 DFS。

現在需要支援 push back、push front、pop back、pop front、求揹包。

這個可以透過兩個棧模擬 deque 完成。

時間複雜度 \(O(q \max p)\)

constexpr int N = 2e3 + 1, M = 3e4 + 5, INF = 1e9;
int n, m, q, id[M], ans[M];
vector<int> G[M];
vector<pair<int, int>> qry[M];
tuple<int, int, int> upd[M];

array<int, N> operator * (array<int, N> x, pii y) {
	for (int i = N - 1; i >= y.fir; i --)
		cmax(x[i], x[i - y.fir] + y.sec);
	return x;
}

struct Stack {
	vector<pair<int, int>> stk;
	vector<array<int, N>> ans;
	
	Stack() {
		array<int, N> ori;
		for (int i = 0; i < N; i ++) ori[i] = 0;
		ans.emplace_back(ori); return;
	}
	void Push(pii x) {
		stk.emplace_back(x);
		auto ret = ans.back() * x;
		ans.emplace_back(ret); return;
	}
	void Pop() { ans.pop_back(), stk.pop_back(); return; }
	pii Top() { return stk.back(); }
	int Query(int x) { return ans.back()[x]; }
	int Size() { return stk.size(); }
	bool Empty() { return stk.empty(); }
};
struct Deque {
	Stack stk[3];
	
	Deque() { return; }
	void Move(int o1, int o2) {
		if (stk[o2].Size()) return;
		int cnt = stk[o1].Size() >> 1;
		while (cnt --) stk[2].Push(stk[o1].Top()), stk[o1].Pop();
		while (stk[o1].Size()) stk[o2].Push(stk[o1].Top()), stk[o1].Pop();
		while (stk[2].Size()) stk[o1].Push(stk[2].Top()), stk[2].Pop();
		return;
	}
	int Query(int x) {
		if (stk[0].Empty() && stk[1].Empty()) return 0;
		if (stk[0].Empty()) return stk[1].Query(x);
		if (stk[1].Empty()) return stk[0].Query(x);
		int ans = - INF;
		for (int i = 0; i <= x; i ++)
			cmax(ans, stk[0].Query(i) + stk[1].Query(x - i));
		return ans;
	}
	void Push_Front(pii x) { stk[0].Push(x); return; }
	void Push_Back(pii x) { stk[1].Push(x); return; }
	void Pop_Front() { Move(1, 0); stk[0].Pop(); return; }
	void Pop_Back() { Move(0, 1); stk[1].Pop(); return; }
	pii Front() { Move(1, 0); return stk[0].Top(); }
	pii Back() { Move(0, 1); return stk[1].Top(); }
	int Size() { return stk[0].Size() + stk[1].Size(); }
	bool Empty() { return stk[0].Empty() && stk[1].Empty(); }
	void Print() {
		for (int i = 0; i <= 10; i ++)
			cout << Query(i) << ' '; cout << endl;
		return;
	}
};

void slv() {
	Read(m);
	int cur = 0; id[n ++] = cur ++;
	upd[0] = mkt(-1, -1, -1);
	for (int i = 0; i < m; i ++) {
		int opt, u; Read(opt, u), u --;
		if (opt == 1) {
			id[n ++] = cur;
			G[id[u]].emplace_back(cur);
			upd[cur] = mkt(-1, -1, -1), cur ++;
		} else if (opt == 2) {
			int p, t; Read(p, t);
			G[id[u]].emplace_back(cur);
			upd[id[u] = cur] = mkt(0, p, t), cur ++;
		} else if (opt == 3) {
			G[id[u]].emplace_back(cur);
			upd[id[u] = cur] = mkt(1, 0, 0), cur ++;
		} else {
			int p = Read<int>();
			qry[id[u]].emplace_back(p, q ++);
		}
	}
	Deque Q;
	auto DFS = [&](auto self, int u) -> void {
		auto [o, p, t] = upd[u];
		if (o == 0) Q.Push_Back(mkp(p, t));
		if (o == 1) tie(p, t) = Q.Front(), Q.Pop_Front();
		for (auto [x, id] : qry[u]) ans[id] = Q.Query(x);
		for (auto v : G[u]) self(self, v);
		if (o == 0) Q.Pop_Back();
		if (o == 1) Q.Push_Front(mkp(p, t));
		return;
	}; DFS(DFS, 0);
	for (int i = 0; i < q; i ++) Write(ans[i], '\n');
	return;
}

相關文章