AtCoder Beginner Contest 395
A - Strictly Increasing?
题意:判断A是不是严格递增。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 1; i < n; ++ i) {
if (a[i] <= a[i - 1]) {
std::cout << "No\n";
return;
}
}
std::cout << "Yes\n";
}
B - Make Target
按题意直接模拟模拟。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<std::string> s(n, std::string(n, '.'));
for (int i = 0; i < n; ++ i) {
int j = n - i - 1;
if (i <= j) {
char c = i % 2 ? '.' : '#';
for (int x = i; x <= j; ++ x) {
for (int y = i; y <= j; ++ y) {
s[x][y] = c;
}
}
}
}
for (int i = 0; i < n; ++ i) {
std::cout << s[i] << "\n";
}
}
C - Shortest Duplicate Subarray
题意:求最短的有至少两个一样元素的子数组长度。
从前往后记录每个数出现的上一个位置。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
const int N = 1e6 + 5;
std::vector<int> last(N, -1);
int ans = -1;
for (int i = 0; i < n; ++ i) {
if (last[a[i]] != -1) {
if (ans == -1 || i - last[a[i]] + 1 < ans) {
ans = i - last[a[i]] + 1;
}
}
last[a[i]] = i;
}
std::cout << ans << "\n";
}
D - Pigeon Swap
题意:有\(n\)个巢穴,第\(i\)个鸽子在第\(i\)个巢穴。有三种操作:
- 把第\(i\)个鸽子放到第\(j\)个巢穴。
- 把第\(i\)个巢穴的鸽子和第\(j\)个巢穴的鸽子交换。
- 询问第\(i\)个鸽子在第几个巢穴。
转换一下题意,第\(i\)个巢穴上贴上了编号为\(i\)的标签,第二个操作视为交换两个巢穴的标签,第三个操作视为询问鸽子所在巢穴的标签。
那么记\(ida_i\)为第\(i\)个鸽子所在的巢穴的标签编号,\(idb_i\)表示第\(i\)个巢穴上面的标签编号, \(idc_i\)表示第\(i\)个标签所在的巢穴编号。
那么对于每个询问,我们直接输出\(idc_{ida_i}\)。对于操作一,就是\(ida_i = idb_j\),对于操作二,我们需要交换两个巢穴的编号,那么需要更新\(idb\)以及\(idc\),先\(swap(idc_{idb_i}, idc_{idb_j})\),交换两个标签的巢穴编号,再\(swap(idb_i, idb_j)\),交换两个巢穴的标签。
点击查看代码
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> ida(n), idb(n), idc(n);
std::iota(ida.begin(), ida.end(), 0);
std::iota(idb.begin(), idb.end(), 0);
std::iota(idc.begin(), idc.end(), 0);
while (q -- ) {
int op;
std::cin >> op;
if (op == 1) {
int a, b;
std::cin >> a >> b;
-- a, -- b;
ida[a] = idb[b];
} else if (op == 2) {
int a, b;
std::cin >> a >> b;
-- a, -- b;
std::swap(idc[idb[a]], idc[idb[b]]);
std::swap(idb[a], idb[b]);
} else {
int a;
std::cin >> a;
-- a;
std::cout << idc[ida[a]] + 1 << "\n";
}
}
}
E - Flip Edge
题意:给你一个有向图,你可以花1的代价按边走,或者花费\(x\)的代价使得所有边翻转。求\(1\)到\(n\)的最小花费。
存一个原图和反图,然后记\(dist[i][j]\)为在\(i\)点且图是不是反的状态的最短距离。
然后就可以\(dijkstra\)。
点击查看代码
void solve() {
int n, m, x;
std::cin >> n >> m >> x;
std::vector adj(2, std::vector(n, std::vector<int>{}));
for (int i = 0; i < m; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
adj[0][u].push_back(v);
adj[1][v].push_back(u);
}
const i64 inf = 1e18;
std::vector dist(n, std::array<i64, 2>{inf, inf});
using A = std::array<i64, 3>;
std::priority_queue<A, std::vector<A>, std::greater<A>> heap;
dist[0][0] = 0;
heap.push({dist[0][0], 0, 0});
while (heap.size()) {
auto [d, u, t] = heap.top(); heap.pop();
if (d != dist[u][t]) {
continue;
}
for (auto & v : adj[t][u]) {
if (dist[v][t] > dist[u][t] + 1) {
dist[v][t] = dist[u][t] + 1;
heap.push({dist[v][t], v, t});
}
}
for (auto & v : adj[t ^ 1][u]) {
if (dist[v][t ^ 1] > dist[u][t] + x + 1) {
dist[v][t ^ 1] = dist[u][t] + x + 1;
heap.push({dist[v][t ^ 1], v, t ^ 1});
}
}
}
std::cout << std::min(dist[n - 1][0], dist[n - 1][1]) << "\n";
}
F - Smooth Occlusion
题意:给你两个数组\(a, b\),你可以让\(a, b\)里的任意数减少任意值,但要大于0。使得满足\(\forall i, j \in [1, n], a_i + b_i = a_j + b_j\)且\(\forall i \in [1, n - 1],|a_i - a_{i+1}| \leq x \ and\ |b_i - b_{i+1}| \leq x\)。求减少的最小值。
先考虑满足任意相邻的两个数相差不超过\(x\)。那么我们从前往后扫一遍,使得\(a_i = \min(a_i, a_{i-1} + x)\),然后从后往前扫一遍,使得\(a_i = \min(a_i, a_{i+1} + x)\)。同时对\(b\)也这么做。那么这样后,每个数就是满足条件的最大值了。于是我们取最小的\(a_i + b_i\),让其它位置的总和也减到这个长度就行了。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<i64> a(n), b(n);
i64 sum = 0;
for (int i = 0; i < n; ++ i) {
std::cin >> a[i] >> b[i];
sum += a[i] + b[i];
}
for (int i = 1; i < n; ++ i) {
a[i] = std::min(a[i], a[i - 1] + m);
b[i] = std::min(b[i], b[i - 1] + m);
}
for (int i = n - 2; i >= 0; -- i) {
a[i] = std::min(a[i], a[i + 1] + m);
b[i] = std::min(b[i], b[i + 1] + m);
}
i64 min = 2e9;
for (int i = 0; i < n; ++ i) {
min = std::min(min, a[i] + b[i]);
}
std::cout << sum - n * min << "\n";
}

浙公网安备 33010602011771号