AtCoder Beginner Contest 338
A - Capitalized?
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
string s;
cin >> s;
if (s[0] >= 'A' and s[0] <= 'Z') {
for (int i = 1; i < s.size(); i++) {
if (s[i] >= 'a' and s[i] <= 'z') continue;
cout << "No\n";
return 0;
}
cout << "Yes\n";
} else {
cout << "No\n";
}
return 0;
}
B - Frequency
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
string s;
cin >> s;
vi cnt(26);
for( auto i : s ) cnt[i-'a'] ++;
int t = *max_element(cnt.begin(), cnt.end());
for( int i = 0 ; i < 26 ; i ++ ){
if( t == cnt[i] ){
cout << (char)(i+'a');
return 0;
}
}
return 0;
}
C - Leftover Recipes
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
int n;
cin >> n;
vi q(n), a(n), b(n);
for (auto &i: q) cin >> i;
for (auto &i: a) cin >> i;
for (auto &i: b) cin >> i;
int res = 0;
for (int x = 0, y; true; x++) {
y = inf;
auto c = q;
for (int i = 0; i < n; i++)
c[i] -= a[i] * x;
if (*min_element(c.begin(), c.end()) < 0) break;
for (int i = 0; i < n; i++)
if( b[i] > 0 ) y = min(y, c[i] / b[i]);
res = max(res, x + y);
}
cout << res << "\n";
return 0;
}
D - Island Tour
这题是个比较有意思的贪心。
首先我们可以在不删边的情况下求出最短的走法,然后可以在计算的过程中求出如果某一条边被删掉会导致哪些路径需要换方向,并且累加换方向要多走的长度。最终贪心的删掉多走长度最短的路即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vi a(m);
for (auto &i: a) cin >> i;
vi b(n + 1);
auto op = [n, &b](int l, int r) {
if (l > r) swap(l, r);
int t = abs((r - l) - (n - r + l));
if (t == 0) return;
if (r - l < n - r + l) b[l] += t, b[r] -= t;
else b[1] += t, b[l] -= t, b[r] += t;
};
for (int i = 1; i < m; i++)
op(a[i - 1], a[i]);
for (int i = 1; i <= n; i++)
b[i] += b[i - 1];
int t = 1;
for (int i = 2; i <= n; i++)
if (b[i] < b[t]) t = i;
int res = 0;
for (int i = 1; i < m; i++) {
if (a[i] <= t and a[i - 1] <= t)
res += abs(a[i] - a[i - 1]);
else if (a[i] > t and a[i - 1] > t)
res += abs(a[i] - a[i - 1]);
else
res += n - abs(a[i] - a[i - 1]);
}
cout << res << "\n";
return 0;
}
E - Chords
这题可以把所有的点对放在一维的数轴上,然后求一下有没有两个区间相交的情况。注意包含的情况不算相交。至于判断相交,我采用的是ST实现了求区间最值。
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<pii> a(n);
for (auto &[x, y]: a) {
cin >> x >> y;
if (x > y)swap(x, y);
}
sort(a.begin(), a.end());
int logN = log2(n) + 1;
auto f = vector(n, vi(logN + 1));
for (int i = 0; i < n; i++)
f[i][0] = a[i].second;
for (int j = 1; j <= logN; j++)
for (int i = 0; i + (1 << j) - 1 < n; i++)
f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
auto calc = [f](int l, int r) -> int {
int s = log2(r - l + 1);
return max(f[l][s], f[r - (1 << s) + 1][s]);
};
for (int i = 0, j, l, r; i < n; i++) {
l = i, r = n - 1, j = i;
for (int mid; l <= r;) {
mid = (l + r) / 2;
if (a[mid].first <= a[i].second) j = mid, l = mid + 1;
else r = mid - 1;
}
if (calc(i, j) > a[i].second) {
cout << "Yes\n";
return 0;
}
}
cout << "No\n";
return 0;
}s
但是赛后经过思考,我发现其实可以用括号匹配来实现,如果存在失配的情况就说明存在了交点。
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(2 * n + 1);
for (int i = 1, l, r; i <= n; i++) {
cin >> l >> r;
if (l > r) swap(l, r);
a[r] = l;
}
stack<int> stk;
for (int i = 1; i <= n * 2; i++) {
if (a[i] == 0) stk.push(i);
else {
if (stk.top() == a[i]) stk.pop();
else {
cout << "Yes\n";
return 0;
}
}
}
cout << "No\n";
return 0;
}
F - Negative Traveling Salesman
状压dp,\(f[i][j]\)表示当前访问过的点集是\(i\)且当前在\(j\)点的最小花费。
首先使用bellman-ford更新已经访问过的点集内部,然后再枚举点集向外走一步。
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto &[u, v, w]: e)
cin >> u >> v >> w, u--, v--;
vector f(1 << n, vi(n, INF));
for (int i = 0; i < n; i++) f[1 << i][i] = 0;
for (int i = 0; i < (1 << n); i++) {
for (bool flag = false; true; flag = false) {
for (const auto &[u, v, w]: e) {
if (f[i][v] <= f[i][u] + w) continue;
flag |= true, f[i][v] = f[i][u] + w;
}
if (flag == false) break;
}
for (const auto &[u, v, w]: e)
f[i | (1 << v)][v] = min(f[i | (1 << v)][v], f[i][u] + w);
}
int res = *min_element(f.back().begin(), f.back().end());
if (res >= inf) {
cout << "No\n";
} else cout << res << "\n";
return 0;
}