1. 程式人生 > 資訊 >毅力號拍到高清火星環境圖,神似戈壁灘

毅力號拍到高清火星環境圖,神似戈壁灘

比賽連結:https://atcoder.jp/contests/abc205

A - kcal

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);
    double a, b;
    cin >> a >> b;
    cout << a * b / 100 << "\n";
    return 0;
}

B - Permutation Check

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<bool> have(n);
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        --x;
        have[x] = true;
    }
    cout << (count(have.begin(), have.end(), true) == n ? "Yes" : "No") << "\n";
    return 0;
}

C - POW

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int a, b, c;
    cin >> a >> b >> c;
    auto cal = [](int a, int b) {
        return a > b ? '>' : (a == b ? '=' : '<');
    };
    cout << (c % 2 == 0 ? cal(abs(a), abs(b)) : cal(a, b)) << "\n";
    return 0;
}

D - Kth Excluded

題意

從小到大給出 \(n\) 個正整數,問這些數外的第 \(k\) 大正整數。

題解

計算第 \(i\) 個數對當前位最小值 \(i\) 的溢位情況,二分第一個溢位不小於 \(k\) 的位置,取前面的數及其溢位情況即可。

程式碼

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, q;
    cin >> n >> q;
    vector<long long> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    vector<long long> exceed(n + 1);
    for (int i = 1; i <= n; i++) {
        exceed[i] = a[i] - i;
    }
    while (q--) {
        long long k;
        cin >> k;
        int pos = lower_bound(exceed.begin(), exceed.end(), k) - exceed.begin();
        cout << a[pos - 1] + (k - exceed[pos - 1]) << "\n";
    }
    return 0;
}

E - White and Black Balls

題意

\(n\) 個白球和 \(m\) 個黑球,現要將這些球排成一排,要求

  • 在所有長度的字首中,白球的個數均不多於黑球 \(k\)

問有多少種排列方式。

題解

CF1536C 的思想類似,將球的新增視作平面上點的移動,不妨將白球看作縱座標 \(y\) ,黑球看作橫座標 \(x\) ,本題即從 \((0, 0)\)\((m, n)\) 的移動過程,共有 \(C_{m + n}^{m}\) 種排列方式。

又有 \(y \le x + k\) ,即:

因為不合法的情況(路徑)一定會與 \(y = x + k + 1\) 有交點,不妨將 \((0, 0)\) 關於該直線對稱,得到點 \((- k - 1, k + 1)\) ,不合法的情況即轉化為從 \((- k - 1, k + 1)\) 移動到 \((m, n)\) 的情況,共有 \(C_{m + n}^{m + k + 1}\) 種情況。

綜上,除去一開始白球比黑球多 \(k\) 個無解的情況,答案為 \(C_{m + n}^{m} - C_{m + n}^{m + k + 1}\)

程式碼

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2e6 + 10;
constexpr int MOD = 1e9 + 7;

int fac[N], inv[N];

int binpow(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1LL * res * a % MOD;
        a = 1LL * a * a % MOD;
        b >>= 1;
    }
    return res;
}

int C(int n, int m){
    if(m < 0 or m > n) return 0;
    return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}

void Init(){
    fac[0] = 1;
    for (int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MOD;
    inv[N - 1] = binpow(fac[N - 1], MOD - 2);
    for (int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    Init();
    int n, m, k;
    cin >> n >> m >> k;
    if (n - m > k) {
        cout << 0 << "\n";
    } else {
        cout << (C(m + n, m) - C(m + n, m + k + 1) + MOD) % MOD << "\n";
    }
    return 0;
}

F - Grid and Tokens

題意

給出一個 \(h \times w\) 的網格,有 \(n\) 個人,第 \(i\) 個人可以選擇 \(a_i \sim c_i\)\(b_i \sim d_i\) 列中的某個網格,一個網格只能被一個人選擇,問最多有多少人可以都選到一個網格。

題解

將問題轉化為最大流問題,每個人可選擇一個網格即轉化為容量為 \(1\) 的邊 \((u_i, v_i)\) ,可選擇的行即轉化為 \(u_i\) 前的結點 \(r_{a_i \sim c_i}\) ,可選擇的列即轉化為 \(v_i\) 後的結點 \(c_{b_i \sim d_i}\) ,多人可選擇即轉化為 \(r_i\) 前的超級源點 \(src\)\(c_i\) 後的超級匯點 \(dst\) ,兩者間的最大流即最多有多少人可以都選到一個網格。

程式碼

#include <bits/stdc++.h>
#include <atcoder/maxflow>
using namespace std;
using namespace atcoder;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int h, w, n;
    cin >> h >> w >> n;
    map<int, int> row, col, u, v;
    for (int i = 0; i < h; i++) {
        row[i] = i + 1;
    }
    for (int i = 0; i < w; i++) {
        col[i] = i + 1 + h;
    }
    for (int i = 0; i < n; i++) {
        u[i] = i + 1 + h + w;
    }
    for (int i = 0; i < n; i++) {
        v[i] = i + 1 + h + w + n;
    }
    int src = 0, dst = h + w + 2 * n + 1;
    mf_graph<int> graph(dst + 1);
    for (int i = 0; i < h; i++) {
        graph.add_edge(src, row[i], 1);
    }
    for (int i = 0; i < w; i++) {
        graph.add_edge(col[i], dst, 1);
    }
    for (int i = 0; i < n; i++) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        --a, --b;
        graph.add_edge(u[i], v[i], 1);
        for (int j = a; j < c; j++) {
            graph.add_edge(row[j], u[i], 1);
        }
        for (int j = b; j < d; j++) {
            graph.add_edge(v[i], col[j], 1);
        }
    }
    cout << graph.flow(src, dst) << "\n";
    return 0;
}

參考

D:

https://atcoder.jp/contests/abc205/editorial/2079

E:

https://atcoder.jp/contests/abc205/editorial/2080

F:

https://atcoder.jp/contests/abc205/editorial/2081

https://codeforces.com/blog/entry/91733?#comment-803511

後記

三門大作業和一堆實驗終於都做完啦ヽ(✿゚▽゚)ノ

剩下的就只剩在充裕的時間裡複習準備期末考試了,好耶( ̄▽ ̄)

時間真是快啊,不知不覺學長學姐們都已經畢業了,祝學長學姐們學業有成,工作順利 ~

明年這個時候就該自己啦 ╰( ̄ω ̄o)