比赛链接:Atcoder Beginner Contest 395
Github 链接:ABC395

A - Strictly Increasing?

按照题意模拟。

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    bool flag = true;
    for (int i = 1; i < n; i++)
        if (a[i] <= a[i - 1]) {
            flag = false;
            break;
        }
    if (flag) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

B - Make Target

按照题意模拟。

#include <bits/stdc++.h>
using namespace std;

char s[55][55];

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int j = n - i + 1;
        if (i <= j) {
            char c;
            if (i & 1) c = '#';
            else c = '.';
            for (int x = i; x <= j; x++)
                for (int y = i; y <= j; y++) s[x][y] = c;
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cout << s[i][j];
        }
        cout << endl;
    }
    return 0;
}

C - Shortest Duplicate Subarray

对于每一个相同的 a a a 的值,记录他们的下标,答案是相距最近的两个相同的 a a a 值的距离

时间复杂度: O ( N + A ) O(N + A) O(N+A) A A A 代表 A i A_i Ai 的最大值)。

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int n, a[N], maxm = 0;

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        maxm = max(a[i], maxm);
    }
    vector<vector<int>> vis(maxm + 1);
    for (int i = 1; i <= n; i++) vis[a[i]].push_back(i);
    int ans = INT_MAX;
    for (int i = 1; i <= maxm; i++) {
        if (vis[i].size() >= 2) {
            for (int j = 1; j < vis[i].size(); j++)
                ans = min(ans, vis[i][j] - vis[i][j - 1] + 1);
        }
    }
    if (ans != INT_MAX) cout << ans << endl;
    else cout << -1 << endl;
    return 0;
}

D - Pigeon Swap

  • 对于第一种操作,只需要对每一个鸽子记录一个 f i f_i fi,表示第 i i i 只鸽子所在的鸟巢编号。
  • 对于第二种操作,
    • 要将所有 f i = a f_i = a fi=a 的位置,变成 f i = b f_i = b fi=b
    • 同时将所有 f i = b f_i = b fi=b 的位置,变成 f i = a f_i = a fi=a
      如果暴力的做,那么时间复杂度是 O ( n ) O(n) O(n),无法满足题目限制。
  • 可以发现 f i f_i fi 的值跟最终的鸟巢编号存在一个映射的关系,所以记录一个 p o s i pos_i posi 来表示这个映射关系。初始化 p o s i = i pos_i = i posi=i,表示最开始每一个 f i f_i fi 的值都表示对应的鸟巢。对于第二种操作,只需要更改对应的映射关系即可,即交换 p o s a pos_a posa p o s b pos_b posb 的值。
  • 但此事第一个操作就不能直接赋值 f i = b f_i = b fi=b 了,而是要让 f i = j f_i = j fi=j p o s j = b pos_j = b posj=b),所以要另外再记一个 i d x i idx_i idxi 作为跟 p o s i pos_i posi 刚好相反的一个映射,方便进行操作一。

在这样的情况下,

  • 操作一实际上就是让 f a = i d x b f_a = idx_b fa=idxb
  • 操作二实际上是要分别交换 ( p o s i d x a pos_{idx_a} posidxa, p o s i d x b pos_{idx_b} posidxb),跟( p o s a pos_a posa, p o s b pos_b posb)。
  • 操作三实际上是要输出 p o s f a pos_{f_a} posfa

时间复杂度: O ( N + Q ) O(N + Q) O(N+Q)

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;
int n, q, f[N], pos[N], idx[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> q;
    for (int i = 1; i <= n; i++) f[i] = pos[i] = idx[i] = i;
    while (q--) {
        int op, a, b;
        cin >> op;
        if (op == 1) {
            cin >> a >> b;
            f[a] = idx[b];
        }
        if (op == 2) {
            cin >> a >> b;
            swap(pos[idx[a]], pos[idx[b]]);
            swap(idx[a], idx[b]);
        }
        if (op == 3) {
            cin >> a;
            cout << pos[f[a]] << '\n';
        }
    }
    return 0;
}

E - Flip Edge

对于每一对给出的 ( u , v ) (u, v) (u,v),直接连一条有向边,权值为 1 1 1

为了表示翻转操作,可以给 ( v + n , u + n ) (v + n, u + n) (v+n,u+n) 连一条边,权值为 1 1 1,并且对于 1 ≤ i ≤ n 1 \le i \le n 1in,连 ( i , i + n ) (i, i + n) (i,i+n) ( i + n , i ) (i + n, i) (i+n,i) 两条边,权值都设为 x x x

接着,直接从 1 1 1 号节点开始跑 d i j s k t r a dijsktra dijsktra,最后的答案为 min ⁡ ( d i s n , d i s 2 n ) \min(dis_n, dis_{2n}) min(disn,dis2n)

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5 + 10, M = N << 3;
int n, m, x, head[N << 1], num = 0, dis[N << 1], vis[N << 1] = { 0 };
struct edge { int to, nxt, w; } e[M];
struct node {
    int u, d;
    bool operator< (const node &curNode) const {
        return curNode.d < d;
    }
};

void addEdge(int u, int v, int w) { e[++num] = (edge){ v, head[u], w}, head[u] = num; }

void dijsktra(int s) {
    for (int i = 1; i <= 2 * n; i++) dis[i] = LLONG_MAX;
    dis[s] = 0;
    priority_queue<node> q;
    q.push({s, 0});
    while (!q.empty()) {
        int u = q.top().u; q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to, w = e[i].w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                q.push({v, dis[v]});
            }
        }
    }
}

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m >> x;
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        addEdge(u, v, 1), addEdge(v + n, u + n, 1);
    }
    for (int i = 1; i <= n; i++) addEdge(i, i + n, x), addEdge(i + n, i, x);
    dijsktra(1);
    cout << min(dis[n], dis[2 * n]) << endl;
    return 0;
}

F - Smooth Occlusion

可以发现 H H H 满足单调性( H H H 越大花费越少),我们可以二分 H H H,然后 O ( n ) O(n) O(n) 检查是不是符合条件。

检查实现:

  • 对于每一个位置 i i i,需要进行的消除次数是 U i + D i − H U_i + D_i - H Ui+DiH
  • 为了满足 ∣ U i − U i + 1 ∣ ≤ X |U_i - U_{i + 1}| \le X UiUi+1X 的条件, U i + 1 U_{i + 1} Ui+1 可行的范围是 [ min ⁡ U i − X , max ⁡ U i + X ] [\min U_i - X, \max U_i + X] [minUiX,maxUi+X]
  • min ⁡ U i = max ⁡ ( 0 , U i − ( U i + D i − H ) ) = max ⁡ ( 0 , H − D i ) \min U_i = \max(0, U_i - (U_i + D_i - H)) = \max (0, H - D_i) minUi=max(0,Ui(Ui+DiH))=max(0,HDi) max ⁡ U i = U i \max U_i = U_i maxUi=Ui

时间复杂度: O ( N log ⁡ ( U i + D i ) ) O(N \log(U_i + D_i)) O(Nlog(Ui+Di))

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5 + 10;
int n, x, u[N], d[N];

bool check(int mid) {
    int l = LLONG_MIN, r = LLONG_MAX;
    for (int i = 1; i <= n; i++) {
        l = max(l, max(0LL, mid - d[i])), r = min(r, u[i]);
        if (l > r) return false;
        l -= x, r += x;
    }
    return true;
}

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> x;
    int l = 0LL, r = LLONG_MAX, tar = 0LL;
    for (int i = 1; i <= n; i++) cin >> u[i] >> d[i], r = min(r, u[i] + d[i]);
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) l = mid + 1, tar = mid;
        else r = mid - 1;
    }
    int ans = 0LL;
    for (int i = 1; i <= n; i++) ans += u[i] + d[i] - tar;
    cout << ans << endl;
    return 0;
}
Logo

集算法之大成!助力oier实现梦想!

更多推荐