AtCoder ABC 181 个人题解(本场GJ x 3)

补题链接:Here

A - Heavy Rotation

N 进行奇偶判断,奇数穿 Black 、偶数穿 White

B - Trapezoid Sum

n 项和公式:Sn=n(a1+an)2

简单套公式计算即可。

注意点:使用 long long

C - Collinearity

题意:给 N 组坐标,判断这些坐标中,是否存在三个不同点处于同一条直线。如果存在,输出 Yes,否则输出 No。

本题是一个数学题,假设我们有三个点,坐标分别为:点 A 为 (x1, y1)、点 B 为 (x2, y2) 和点 C 为 (x3, y3)。

判断三点共线

假设这三个点共线,则

|y2y1x2x1|=|y3y1x3x1|

这样我们可以变换为

(y2y1)×(x3x1)=(y3y1)×(x2x1)

由于本题数据范围较小可以暴力遍历

  • O(N3)
#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 的倍数。

  • 1N2×105

思路:

在数学问题上,有以下是成立的

  • 判断最后一个数字是否为 2 的倍数:只要判断最后一位是否为 2 的倍数;
  • 判断最后一个数字是否为 4 的倍数:只需判断最后两个数字是否为 4 的倍数;
  • 判断最后三个数字是否为 8 的倍数:只需判断最后三位数字是否为 8 的倍数。

通常,为 2k 的倍数等效于使最后 k 个数字为 2k 的倍数。 让我简要地展示8的倍数的情况。

1000=23×53

注意:1000 可被 8 整除,因此,对于任何整数 n ,可令 qn 除以 1000 的商,r 为余数

即:n=1000q+r

故此,r 恰好为 n 的最后三位数。

此时:n1000q+r( mod 8)


现在回到原来的问题上;

关于 S 是否为 8 的倍数,我们进行分情况讨论

  • |S|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 个整数 H1HnW 配对成 N+12
  • 统计 【数值查】总和的最小值

数据范围:

  • 1N,M2×105

思路:

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×109 的网格,其中横坐标区间为 [−100,100],纵坐标区间为 [109,109]。平面上有若干个点。
你有一个圆,最开始在 (0,109),询问圆半径最大是多少使得它可以在不接触点的情况下圆心到达 (0,109)

思路:

二分圆的直径,如果两个点之间的距离小于直径,那么显然圆没法从这两个点之间经过。注意要把直线 x=100x=100 也看做一个点。

那么如果连完线之后把直线 x=100x=100 联通,那么相当于存在若干连线将左右两边隔开,这样圆就无法过去。否则可以到达。
用并查集维护即可。

  • O(n2logk)
#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;
}
posted @   RioTian  阅读(145)  评论(1编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
点击右上角即可分享
微信分享提示

📖目录