ABC229 复盘

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;
}
posted @ 2024-04-17 21:00  2020luke  阅读(64)  评论(0)    收藏  举报