T1:录制节目

可以将原题转化成

n 条线段,可以保留若干条线段,并且可以分成两部分,使得每部分的线段互不相交

先将所有线段按右端点做升序排序,且按左端点做降序排序
然后维护两个变量 last1last2
last1:第一个部分的最后的端点
last2:第二个部分的最后的端点
尽量让 min(last1,last2) 更小

原题:P2255

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
struct line {
int l, r;
bool operator<(const line& o) const {
if (r == o.r) return l > o.l;
return r < o.r;
};
};
int main() {
int n;
cin >> n;
vector<line> d(n);
rep(i, n) cin >> d[i].l >> d[i].r;
sort(d.begin(), d.end());
int ans = 0;
int last1 = 0, last2 = 0;
for (auto [l, r] : d) {
if (last1 < last2) swap(last1, last2);
if (l >= last1) {
ans++;
last1 = r;
}
else if (l >= last2) {
ans++;
last2 = r;
}
}
cout << ans << '\n';
return 0;
}

T2:算式求值(二)

原题:基本计算器

代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
string s;
cin >> s;
int n = s.size();
ll ans = 0;
int sign = 1;
stack<int> ops;
ops.push(1);
int i = 0;
while (i < n) {
if (s[i] == '+') {
sign = ops.top();
i++;
}
else if (s[i] == '-') {
sign = -ops.top();
i++;
}
else if (s[i] == '(') {
ops.push(sign);
i++;
}
else if (s[i] == ')') {
ops.pop();
i++;
}
else {
ll num = 0;
while (i < n and isdigit(s[i])) {
num = num*10 + s[i]-'0';
i++;
}
ans += sign * num;
}
}
cout << ans << '\n';
return 0;
}

T3:田忌赛马

先将 ab 做升序排序

然后进行分类讨论:

  • 如果 a 剩下的最小值大于 b 剩下的最小值,则用 a 剩下的最小值来打 b 剩下的最小值
  • 如果 a 剩下的最大值大于 b 剩下的最大值,则用 a 剩下的最大值来大 b 剩下的最大值
  • 否则用 a 最小的去消耗 b 最大的

原题:P1650

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), b(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
sort(a.begin(), a.end());
sort(b.begin(), b.end());
int ans = 0;
int l1 = 0, r1 = n-1;
int l2 = 0, r2 = n-1;
while (l1 <= r1 and l2 <= r2) {
if (a[l1] > b[l2]) {
ans++;
l1++; l2++;
}
else if (a[r1] > b[r2]) {
ans++;
r1--; r2--;
}
else {
if (a[l1] < b[r2]) ans--;
l1++; r2--;
}
}
cout << ans << '\n';
return 0;
}

T4:树的颜色

有三种做法:

  • 树上启发式合并
  • 树上莫队
  • 可以用树上 dfs 来统计区间 [in[1],out[v]] 中每个点对 点 v 上颜色 c 的贡献,然后将它容斥掉区间 [in[1],in[v]] 中的点对颜色 c 的贡献,就能求出点 v 的答案。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<vector<int>> to(n);
for (int i = 1; i < n; ++i) {
int p;
cin >> p;
--p;
to[p].push_back(i);
}
vector<int> c(n);
rep(i, n) cin >> c[i], c[i]--;
vector<int> cnt(n), ans(n);
auto dfs = [&](auto& f, int v) -> void {
ans[v] = ++cnt[c[v]];
for (int u : to[v]) {
f(f, u);
}
ans[v] = cnt[c[v]]-ans[v];
};
dfs(dfs, 0);
rep(i, n) cout << ans[i] << ' ';
return 0;
}