ABC229 覆盤

2020luke發表於2024-04-17

ABC229 覆盤

[ABC229C] Cheese

思路解析

題目已經告訴了你每克比薩能帶來的美味度,因此直接以每克的美味度為關鍵字貪心即可。

時間複雜度:一次排序,\(O(n \log n)\)

code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<long long, long long>
#define fir first
#define sec second
const int N = 3e5 + 10;
int n, w;
PII c[N];
bool cmp(PII x, PII y) {
	return x.fir > y.fir;
}
signed main() {
	cin >> n >> w;
	for(int i = 1; i <= n; i++) {
		cin >> c[i].fir >> c[i].sec;
	}
	sort(c + 1, c + n + 1, cmp);
	int sum = 0, ans = 0;
	for(int i = 1; i <= n; i++) {
		if(sum + c[i].sec <= w) {
			ans += c[i].fir * c[i].sec;
			sum += c[i].sec;
		}
		else {
			ans += c[i].fir * (w - sum);
			break;
		}
	}
	cout << ans;
	return 0;
}

[ABC229D] Longest X

思路解析

雙指標,我們可以用一個 \(l,r\) 表示我們當前列舉到的區間,也就是我們想讓整個區間都為 \(\texttt{X}\)\(r\) 一直右移直到 \(l,r\) 之間的 \(\texttt{.}\) 的個數超過 \(k\),此時 \(r-l\) 就是這個區間的長度,答案就是所有這種區間長度的最大值,以及每一次我們擴充完 \(r\)\(l\) 也要右移。

時間複雜度:雙指標,\(l,r\) 都最多走 \(n\) 步,\(O(n)\)

code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
string str;
int k, s[N];
int main() {
	cin >> str >> k;
	int n = str.size();
	str = ' ' + str;
	for(int i = 1; i <= n; i++) {
		s[i] = s[i - 1];
		if(str[i] == '.') s[i]++;
	}
	int l = 1, r = 0, ans = -1;
	while(l <= n) {
		while(s[r] - s[l - 1] <= k && r <= n) r++;
		ans = max(ans, r - l);
		l++;
	}
	cout << ans;
	return 0;
}

[ABC229E] Graph Destruction

思路解析

題目要求刪點,而眾所周知刪點的代價要大於加點的代價,於是我們考慮倒著處理詢問,將每一個刪點改成加點,而加點時就用並查集維護連通塊即可。

時間複雜度:由於需要遍歷到每一條邊,並查集還有一個小常數,\(O(mw)\)\(w\) 為常數。

code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, fa[N];
vector<int> g[N];
int find(int x) {
	if(x == fa[x]) return x;
	return (fa[x] = find(fa[x]), fa[x]);
}
int main() {
	cin >> n >> m;
	for(int i = 1, u, v; i <= m; i++) {
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1; i <= n; i++) fa[i] = i;
	int ans = 0;
	stack<int> st;
	for(int i = n; i >= 1; i--) {
		st.push(ans);
		ans ++;
		for(auto it : g[i]) {
			if(it > i) {
				if(find(it) != find(i)) ans --;
				fa[find(it)] = find(i);
			}
		}
	}
	while(!st.empty()) cout << st.top() << '\n', st.pop();
	return 0;
}

CF118E Bertown roads

思路解析

看到題目將無向邊轉成有向邊求強連通分量就能想到基本是 tarjan 的板子。可以發現題目要求的其實就是橋(割邊,也就是刪掉該邊後整張圖不連通),若有橋,則說明不可能滿足題目的條件;若沒有橋,則邊的方向就是 tarjan 遍歷到的方向。所有條件都可以透過 tarjan 的邊雙連通分量求得,因此跑一遍 tarjan 即可。

code

#include<bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define sec second
#define fir first
const int N = 1e5 + 10, M = 3e5 + 10;
int n, m, dfn[N], low[N], idx = 0, cnt = 0;
struct node {
	int to, nxt;
} g[M << 1];
int head[M << 1], ect = 1;
void add(int u, int v) {
	g[++ect].to = v;
	g[ect].nxt = head[u];
	head[u] = ect;
}
vector<int> dcc[N];
bool vis[N], ve[M << 1], brg;
stack<int> st;
vector< PII > ans;
void tarjan(int u) {
	if(dfn[u]) return;
	dfn[u] = low[u] = ++idx;
	st.push(u);
	for(int i = head[u]; ~i; i = g[i].nxt) {
		int v = g[i].to;
		if(ve[i]) continue;
		ve[i] = ve[i ^ 1] = true;
		ans.push_back({u, v});
		if(!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if(dfn[u] < low[v]) brg = true;
		}
		else low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u]) {
		int v = -1; cnt++;
		while(v != u) {
			v = st.top(); st.pop();
			dcc[cnt].push_back(v);
		}
	}
}
int main() {
	memset(head, -1, sizeof(head));
	cin >> n >> m;
	for(int i = 1, u, v; i <= m; i++) {
		cin >> u >> v;
		add(u, v); add(v, u);
	}
	for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
	if(brg) return (int)(cout << 0, 0);
	for(auto it : ans) cout << it.fir << ' ' << it.sec << '\n';
	return 0;
}