Atcoder Beginner Contest 385
比赛链接: Atcoder Beginner Contest 385
Github 链接:ABC385
A - Equally
只有三个数相等或者两个小的数加起来等于最大的数时输出 Yes,其他时候输出 No。
时间复杂度:\(O(1)\)。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int a[5];
for (int i = 1; i <= 3; i++) cin >> a[i];
sort(a + 1, a + 4);
if (a[1] + a[2] == a[3] || (a[1] == a[2] && a[2] == a[3])) puts("Yes");
else puts("No");
return 0;
}
B - Santa Claus 1
按照题意模拟,用 \(vis\) 数组记录经过的格子,最后统计这些格子中房子 (\(@\)) 的个数。
时间复杂度:\(O(HW + |T|)\) (\(|T|\) 代表字符串 \(T\) 的长度)。
#include <bits/stdc++.h>
using namespace std;
int h, w, x, y, vis[105][105];
string s[150], t;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> h >> w >> x >> y;
for (int i = 1; i <= h; i++) {
cin >> s[i];
s[i] = " " + s[i];
}
cin >> t;
for (int i = 0; i < t.size(); i++) {
if (t[i] == 'U') {
int xx = x - 1, yy = y;
if (s[xx][yy] != '#') x = xx, y = yy, vis[xx][yy] = 1;
}
if (t[i] == 'D') {
int xx = x + 1, yy = y;
if (s[xx][yy] != '#') x = xx, y = yy, vis[xx][yy] = 1;
}
if (t[i] == 'L') {
int xx = x, yy = y - 1;
if (s[xx][yy] != '#') x = xx, y = yy, vis[xx][yy] = 1;
}
if (t[i] == 'R') {
int xx = x, yy = y + 1;
if (s[xx][yy] != '#') x = xx, y = yy, vis[xx][yy] = 1;
}
}
int ans = 0;
for (int i = 1; i <= h; i++)
for (int j = 1; j <= w; j++)
if (vis[i][j] && s[i][j] == '@') ans++;
cout << x << ' ' << y << ' ' << ans << endl;
return 0;
}
C - Illuminate Buildings
设 \(dp_{i, j}\) 表示考虑到第 \(i\) 位,间隔为 \(j\) 能装饰的建筑物数量。当 \(h_i = h_{i - j}\) 时,状态转移方程为 \(dp_{i, j} = max(dp_{i, j}, dp_{i - j, j} + 1)\)。
时间复杂度: \(O(N^2)\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int n, h[N], dp[N][N];
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> h[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) dp[i][j] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (i - j && h[i] != h[i - j]) continue;
dp[i][j] = max(dp[i][j], dp[i - j][j] + 1);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) ans = max(ans, dp[i][j]);
cout << ans << endl;
return 0;
}
D - Santa Claus 2
按照题意模拟过程。
找房子的方法:
- 用两个 \(vector\) \(vx\) 和 \(vy\) 分别存房子的坐标 \((x, y)\) 和对应的 \((y, x)\) 并进行排序。
- 在上下移动的时候,利用二分在 \(vx\) 中找出经过的点存入 \(set\) 里面。
- 在左右移动的时候,利用二分在 \(vy\) 中找出经过的点存入 \(set\) 里面。
时间复杂度:\(O(Mlog^2N)\)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m, x, y;
set<pair<int, int>> vis;
vector<pair<int, int>> vx, vy;
bool cmp(const pair<int, int> &px, const pair<int, int> &py) {
return px.first < py.first || (px.first == py.first && px.second < py.second);
}
pair<int, int> find(int fi, int sel, int ser, const vector<pair<int, int>> &v) {
int L = lower_bound(v.begin(), v.end(), make_pair(fi, sel), cmp) - v.begin();
int R = upper_bound(v.begin(), v.end(), make_pair(fi, ser), cmp) - v.begin() - 1;
return {L, R};
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> x >> y;
for (int i = 1; i <= n; i++) {
int xx, yy;
cin >> xx >> yy;
vx.push_back({xx, yy}), vy.push_back({yy, xx});
}
sort(vx.begin(), vx.end()), sort(vy.begin(), vy.end());
while (m--) {
char op; int c;
cin >> op >> c;
if (op == 'U') {
pair<int, int> ans = find(x, y, y + c, vx);
for (int i = ans.first; i <= ans.second; i++) vis.insert(vx[i]);
y += c;
}
if (op == 'D') {
pair<int, int> ans = find(x, y - c, y, vx);
for (int i = ans.first; i <= ans.second; i++) vis.insert(vx[i]);
y -= c;
}
if (op == 'L') {
pair<int, int> ans = find(y, x - c, x, vy);
for (int i = ans.first; i <= ans.second; i++) vis.insert({vy[i].second, vy[i].first});
x -= c;
}
if (op == 'R') {
pair<int, int> ans = find(y, x, x + c, vy);
for (int i = ans.first; i <= ans.second; i++) vis.insert({vy[i].second, vy[i].first});
x += c;
}
}
cout << x << ' ' << y << ' ' << vis.size() << endl;
return 0;
}
E - Snowflake Tree
可以发现在中心点和 \(x\) 确定之后,整棵雪花树就可以确定下来了。对于每一组中心点和 \(x\),整棵雪花树的节点数量为 \(x \times min(deg_{1 \le i \le x}) + 1\),其中 \(deg\) 表示那 \(x\) 个节点对应的度数。
按照贪心的思想,我们可以枚举中心点,将中心点相邻的点按照度数从大到小进行排序 (\(x\) 相同的情况下 \(min(deg_{1 \le i \le x})\) 越大,结果越优,所以要取最大的 \(x\) 个节点)。枚举 \(x\),计算出对应的节点数量,就可以找到最大的节点数了。
时间复杂度:\(O(N\log K)\),\(K\) 表示节点的最大度数。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int n, ans = 0;
vector<vector<int>> g;
vector<int> deg;
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
g.resize(n + 1), deg.resize(n + 1);
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
deg[u]++, deg[v]++;
}
for (int i = 1; i <= n; i++) {
vector<int> v;
for (int j : g[i]) v.push_back(deg[j]);
sort(v.begin(), v.end(), [](int x, int y){
return x > y;
});
int num = 0, tot = INT_MAX;
for (int j : v) {
num++, tot = min(tot, j);
ans = max(ans, tot * num + 1);
}
}
cout << n - ans << endl;
return 0;
}
F - Visible Buildings
取相邻的两个建筑物,将这两个建筑物的顶点连一条直线,所有之前的截距的最大值就是答案。
为什么要取相邻的:可以证明如果两个建筑物之间还有建筑物,无论中间的建筑物是在直线的上方或者下方,中间的建筑物与两边建筑物的连线至少有一条的截距都大于两端建筑物连线的截距。所以对于同组数据,取相邻的两个建筑物连直线截距一定最大。
对于给定两个建筑物,可以根据建筑物顶点坐标 \((x_{i - 1}, h_{i - 1})\) 和 \((x_i, h_i)\) (\(2 \le i \le N\)) 算出直线的方程。
直线方程为:\(y - h_{i - 1} = \frac{h_i - h_{i - 1}}{x_i - x_{i - 1}}(x - x_{i - 1})\),即 \(y = \frac{h_i - h_{i - 1}}{x_i - x_{i - 1}} x + h_{i - 1} - \frac{h_i - h_{i - 1}}{x_i - x_{i - 1}} x_{i - 1}\)
截距为:\(h_{i - 1} - \frac{h_i - h_{i - 1}}{x_i - x_{i - 1}} x_{i - 1}\)
时间复杂度: \(O(N)\)。
#include <bits/stdc++.h>
using namespace std;
#define double long double
const int N = 2e5 + 10;
int n;
double x[N], h[N], ans = 0.0;
bool ok = false;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> x[i] >> h[i];
for (int i = 2; i <= n; i++) {
double d = h[i - 1] - (h[i] - h[i - 1]) / (x[i] - x[i - 1]) * x[i - 1];
if (d >= 0) ok = true;
ans = max(ans, d);
}
if (ok) cout << fixed << setprecision(10) << ans << endl;
else cout << -1 << endl;
return 0;
}

浙公网安备 33010602011771号