AtCoder ABC 181 我的題解(本場GJ x 3)

補題連接:Hereios

A - Heavy Rotation

\(N\) 進行奇偶判斷,奇數穿 Black 、偶數穿 Whitec++

B - Trapezoid Sum

\(n\) 項和公式:\(S_n = \frac{n(a_1 + a_n)}{2}\)ui

簡單套公式計算便可。spa

注意點:使用 long long.net

C - Collinearity

題意:給 N 組座標,判斷這些座標中,是否存在三個不一樣點處於同一條直線。若是存在,輸出 Yes,不然輸出 No。code

本題是一個數學題,假設咱們有三個點,座標分別爲:點 A 爲 (x1, y1)、點 B 爲 (x2, y2) 和點 C 爲 (x3, y3)。orm

判斷三點共線blog

假設這三個點共線,則排序

\[\left |\frac{y_2-y_1}{x_2-x_1} \right| = \left |\frac{y_3-y_1}{x_3-x_1} \right| \]

這樣咱們能夠變換爲ci

\[(y_2 - y_1)\times(x_3-x_1) = (y_3-y_1)\times(x_2-x_1) \]

因爲本題數據範圍較小能夠暴力遍歷

  • \(\mathcal{O}(N^3)\)
#include <bits/stdc++.h>
using namespace std;
typedef struct _POS {
    int x;
    int y;
} POS;

const int MAXN = 1e2 + 4;
POS arr[MAXN];

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> arr[i].x >> arr[i].y;
    //暴力枚舉
    for (int i = 1; i <= n - 2; i++)
        for (int j = i + 1; j <= n - 1; j++)
            for (int k = j + 1; k <= n; k++)
                if ((arr[k].x - arr[i].x) * (arr[j].y - arr[i].y) ==
                    (arr[j].x - arr[i].x) * (arr[k].y - arr[i].y)) {
                    cout << "Yes\n";
                    return 0;
                }
    cout << "No\n";
    return 0;
}

D - Hachi

核心在於 整數是否能被 \(8\) 整除都取決於後三位

題意:給定一個字符串(由 1 ~ 9 構成),請問是否能經過重排序來使這個字符串整數爲 \(8\) 的倍數。

  • \(1 \le N\le2\times10^5\)

思路:

在數學問題上,有如下是成立的

  • 判斷最後一個數字是否爲 \(2\) 的倍數:只要判斷最後一位是否爲 \(2\) 的倍數;
  • 判斷最後一個數字是否爲 \(4\) 的倍數:只需判斷最後兩個數字是否爲 \(4\) 的倍數;
  • 判斷最後三個數字是否爲 \(8\) 的倍數:只需判斷最後三位數字是否爲 \(8\) 的倍數。

一般,爲 \(2^k\) 的倍數等效於使最後 \(k\) 個數字爲 \(2^k\) 的倍數。 讓我簡要地展現8的倍數的狀況。

\(1000 = 2^3 \times 5^3\)

注意:\(1000\) 可被 \(8\) 整除,所以,對於任何整數 \(n\) ,可令 \(q\)\(n\) 除以 \(1000\) 的商,\(r\) 爲餘數

即:\(n = 1000q + r\)

故此,\(r\) 剛好爲 \(n\) 的最後三位數。

此時:\(n \equiv 1000q + r \equiv (\ mod\ 8)\)


如今回到原來的問題上;

關於 S 是否爲 8 的倍數,咱們進行分狀況討論

  • \(|S| \le 3\) 的狀況咱們能夠直接全排列

  • \(|S| > 4\) 的狀況咱們能夠考慮以下。

    考慮 \(8\) 的倍數的全部可能的後三位數字。 肯定是否能夠從 \(S\) 知足它們中的任何一個。

    實際上 \(1000\) 之內的 \(8\) 的倍數僅 124個,因此運行速度會很快

#incwlude <bits/stdc++.h>
using namespace std;
using ll = long long;
bool solve(string S) {
    if (S.size() <= 5) {
        sort(S.begin(), S.end());
        do {
            int val = 0;
            for (auto c : S) val = val * 10 + (int)(c - '0');
            if (val % 8 == 0) return true;
        } while (next_permutation(S.begin(), S.end()));
        return false;
    }
    vector<int> all(10, 0);
    for (const auto c : S) all[c - '0']++;
    for (int i = 0; i < 1000; i += 8) {
        vector<int> num(10, 0);
        int i2 = i;
        for (int iter = 0; iter < 3; ++iter) {    
            num[i2 % 10]++;
            i2 /= 10;
        }
        bool ok = true;
        for (int v = 0; v < 10; ++v)
            if (num[v] > all[v]) ok = false;
        if (ok) return true;
    }
    return false;
}
int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    string s;
    cin >> s;
    cout << (solve(s) ? "Yes" : "No");
    return 0;
}

E - Transformable Teacher

題意:

給出 N個整數,且N爲奇數,回答M個回答

  • 對於每次查詢都給定一個整數 M
  • \(N + 1\) 個整數 \(H_1,……,H_n,W\) 配對成 \(\frac{N + 1}{2}\)
  • 統計 【數值查】總和的最小值

數據範圍:

  • \(1\le N,M\le 2\times10^5\)

思路:

https://blog.csdn.net/justidle/article/details/109509824

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class T>
void chmax(T &a, T b) {
    if (a < b) a = b;
}

template <class T>
void chmin(T &a, T b) {
    if (a > b) a = b;
}

const ll inf = 1LL << 60;
int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int N, M;
    cin >> N >> M;
    vector<ll> X(N), W(M);
    for (ll &x : X) cin >> x;
    for (ll &x : W) cin >> x;
    sort(X.begin(), X.end());

    vector<ll> left(N + 1, 0), right(N + 1, 0);
    for (int i = 2; i < N; i += 2) {
        left[i]  = left[i - 2] + X[i - 1] - X[i - 2];
        right[i] = right[i - 2] + X[N - i + 1] - X[N - i];
    }
    ll ans = inf;
    for (auto w : W) {
        int i = lower_bound(X.begin(), X.end(), w) - X.begin();
        if (i % 2 == 0) chmin(ans, left[i] + right[N - i - 1] + X[i] - w);
        else
            chmin(ans, left[i - 1] + right[N - i] + w - X[i - 1]);
    }
    cout << ans << '\n';
    return 0;
}

F - Silver Woods

有一個 \(200×2×10^9\) 的網格,其中橫座標區間爲 [−100,100],縱座標區間爲 \([−10^9,10^9]\)。平面上有若干個點。
你有一個圓,最開始在 \((0,−10^9)\),詢問圓半徑最大是多少使得它能夠在不接觸點的狀況下圓心到達 \((0,10^9)\)

思路:

二分圓的直徑,若是兩個點之間的距離小於直徑,那麼顯然圓無法從這兩個點之間通過。注意要把直線 \(x=100\)\(x=−100\) 也看作一個點。

那麼若是連完線以後把直線 \(x=100\)\(x=−100\) 聯通,那麼至關於存在若干連線將左右兩邊隔開,這樣圓就沒法過去。不然能夠到達。
用並查集維護便可。

  • \(\mathcal{O}(n^2logk)\)
#include <bits/stdc++.h>
using namespace std;
using ll   = long long;
using pii  = pair<int, int>;
using Edge = pair<double, pii>;
struct UnionFind {
    vector<int> par;

    UnionFind(int n) : par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

    int find(int x) {
        return par[x] < 0 ? x : par[x] = find(par[x]);
    }

    bool issame(int x, int y) {
        return find(x) == find(y);
    }

    void merge(int x, int y) {
        x = find(x), y = find(y);
        if (x != y) {
            if (par[x] > par[y]) swap(x, y);
            par[x] += par[y];
            par[y] = x;
        }
    }
};

int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    int N;
    cin >> N;
    vector<double> x(N), y(N);
    for (int i = 0; i < N; ++i) cin >> x[i] >> y[i];
    auto calc = [&](int i, int j) -> double {
        return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
    };
    vector<Edge> edges;
    int s = N, t = N + 1;
    for (int i = 0; i < N; ++i) {
        edges.push_back(Edge(100.0 - y[i], pii(s, i)));
        edges.push_back(Edge(100.0 + y[i], pii(t, i)));
        for (int j = i + 1; j < N; ++j) {
            edges.push_back(Edge(calc(i, j), pii(i, j)));
        }
    }
    sort(edges.begin(), edges.end());
    UnionFind uf(N + 2);
    double res = 0.0;
    for (auto e : edges) {
        uf.merge(e.second.first, e.second.second);
        if (uf.issame(s, t)) {
            res = e.first / 2;
            break;
        }
    }
    cout << fixed << setprecision(10) << res << endl;

    return 0;
}
相關文章
相關標籤/搜索