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;
}

浙公网安备 33010602011771号