补题链接:Here

A - Heavy Rotation

AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图1 进行奇偶判断,奇数穿 Black 、偶数穿 White

B - Trapezoid Sum

AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图2 项和公式:AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图3%7D%7B2%7D#card=math&code=S_n%20%3D%20%5Cfrac%7Bn%28a_1%20%2B%20a_n%29%7D%7B2%7D&id=FCaaP)

简单套公式计算即可。

注意点:使用 long long

C - Collinearity

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

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

判断三点共线

假设这三个点共线,则

AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图4

这样我们可以变换为

AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图5%5Ctimes(x_3-x_1)%20%3D%20(y_3-y_1)%5Ctimes(x_2-x_1)%0A#card=math&code=%28y_2%20-%20y_1%29%5Ctimes%28x_3-x_1%29%20%3D%20%28y_3-y_1%29%5Ctimes%28x_2-x_1%29%0A&id=pe4Vy)

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

  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图6#card=math&code=%5Cmathcal%7BO%7D%28N%5E3%29&id=G2EKY)
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef struct _POS {
  4. int x;
  5. int y;
  6. } POS;
  7. const int MAXN = 1e2 + 4;
  8. POS arr[MAXN];
  9. int main() {
  10. int n;
  11. cin >> n;
  12. for (int i = 1; i <= n; i++) cin >> arr[i].x >> arr[i].y;
  13. //暴力枚举
  14. for (int i = 1; i <= n - 2; i++)
  15. for (int j = i + 1; j <= n - 1; j++)
  16. for (int k = j + 1; k <= n; k++)
  17. if ((arr[k].x - arr[i].x) * (arr[j].y - arr[i].y) ==
  18. (arr[j].x - arr[i].x) * (arr[k].y - arr[i].y)) {
  19. cout << "Yes\n";
  20. return 0;
  21. }
  22. cout << "No\n";
  23. return 0;
  24. }

D - Hachi

核心在于 整数是否能被 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图7 整除都取决于后三位

题意:给定一个字符串(由 1 ~ 9 构成),请问是否能通过重排序来使这个字符串整数为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图8 的倍数。

  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图9

思路:

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

  • 判断最后一个数字是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图10 的倍数:只要判断最后一位是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图11 的倍数;
  • 判断最后一个数字是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图12 的倍数:只需判断最后两个数字是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图13 的倍数;
  • 判断最后三个数字是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图14 的倍数:只需判断最后三位数字是否为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图15 的倍数。

通常,为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图16 的倍数等效于使最后 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图17 个数字为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图18 的倍数。 让我简要地展示8的倍数的情况。

AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图19

注意:AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图20 可被 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图21 整除,因此,对于任何整数 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图22 ,可令 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图23AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图24 除以 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图25 的商,AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图26 为余数

即:AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图27

故此,AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图28 恰好为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图29 的最后三位数。

此时:AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图30#card=math&code=n%20%5Cequiv%201000q%20%2B%20r%20%5Cequiv%20%28%5C%20mod%5C%208%29&id=RnUSf)


现在回到原来的问题上;

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

  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图31 的情况我们可以直接全排列
  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图32 的情况我们可以考虑如下。
    考虑 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图33 的倍数的所有可能的后三位数字。 确定是否可以从 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图34 满足它们中的任何一个。

    实际上 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图35 以内的 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图36 的倍数仅 124个,所以运行速度会很快

  1. #incwlude <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. bool solve(string S) {
  5. if (S.size() <= 5) {
  6. sort(S.begin(), S.end());
  7. do {
  8. int val = 0;
  9. for (auto c : S) val = val * 10 + (int)(c - '0');
  10. if (val % 8 == 0) return true;
  11. } while (next_permutation(S.begin(), S.end()));
  12. return false;
  13. }
  14. vector<int> all(10, 0);
  15. for (const auto c : S) all[c - '0']++;
  16. for (int i = 0; i < 1000; i += 8) {
  17. vector<int> num(10, 0);
  18. int i2 = i;
  19. for (int iter = 0; iter < 3; ++iter) {
  20. num[i2 % 10]++;
  21. i2 /= 10;
  22. }
  23. bool ok = true;
  24. for (int v = 0; v < 10; ++v)
  25. if (num[v] > all[v]) ok = false;
  26. if (ok) return true;
  27. }
  28. return false;
  29. }
  30. int main() {
  31. ios_base::sync_with_stdio(false), cin.tie(0);
  32. string s;
  33. cin >> s;
  34. cout << (solve(s) ? "Yes" : "No");
  35. return 0;
  36. }

E - Transformable Teacher

题意:

给出 N个整数,且N为奇数,回答M个回答

  • 对于每次查询都给定一个整数 M
  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图37 个整数 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图38 配对成 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图39
  • 统计 【数值查】总和的最小值

数据范围:

  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图40

思路:

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

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. template <class T>
  5. void chmax(T &a, T b) {
  6. if (a < b) a = b;
  7. }
  8. template <class T>
  9. void chmin(T &a, T b) {
  10. if (a > b) a = b;
  11. }
  12. const ll inf = 1LL << 60;
  13. int main() {
  14. ios_base::sync_with_stdio(false), cin.tie(0);
  15. int N, M;
  16. cin >> N >> M;
  17. vector<ll> X(N), W(M);
  18. for (ll &x : X) cin >> x;
  19. for (ll &x : W) cin >> x;
  20. sort(X.begin(), X.end());
  21. vector<ll> left(N + 1, 0), right(N + 1, 0);
  22. for (int i = 2; i < N; i += 2) {
  23. left[i] = left[i - 2] + X[i - 1] - X[i - 2];
  24. right[i] = right[i - 2] + X[N - i + 1] - X[N - i];
  25. }
  26. ll ans = inf;
  27. for (auto w : W) {
  28. int i = lower_bound(X.begin(), X.end(), w) - X.begin();
  29. if (i % 2 == 0) chmin(ans, left[i] + right[N - i - 1] + X[i] - w);
  30. else
  31. chmin(ans, left[i - 1] + right[N - i] + w - X[i - 1]);
  32. }
  33. cout << ans << '\n';
  34. return 0;
  35. }

F - Silver Woods

有一个 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图41 的网格,其中横坐标区间为 [−100,100],纵坐标区间为 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图42。平面上有若干个点。
你有一个圆,最开始在 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图43#card=math&code=%280%2C%E2%88%9210%5E9%29&id=znz6c),询问圆半径最大是多少使得它可以在不接触点的情况下圆心到达 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图44#card=math&code=%280%2C10%5E9%29&id=euMlE)。

思路:

二分圆的直径,如果两个点之间的距离小于直径,那么显然圆没法从这两个点之间经过。注意要把直线 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图45AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图46 也看做一个点。

那么如果连完线之后把直线 AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图47AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图48 联通,那么相当于存在若干连线将左右两边隔开,这样圆就无法过去。否则可以到达。
用并查集维护即可。

  • AtCoder Beginner Contest 181 个人题解(本场GJ x 3) - 图49#card=math&code=%5Cmathcal%7BO%7D%28n%5E2logk%29&id=UgXJG)
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. using pii = pair<int, int>;
  5. using Edge = pair<double, pii>;
  6. struct UnionFind {
  7. vector<int> par;
  8. UnionFind(int n) : par(n, -1) {}
  9. void init(int n) { par.assign(n, -1); }
  10. int find(int x) {
  11. return par[x] < 0 ? x : par[x] = find(par[x]);
  12. }
  13. bool issame(int x, int y) {
  14. return find(x) == find(y);
  15. }
  16. void merge(int x, int y) {
  17. x = find(x), y = find(y);
  18. if (x != y) {
  19. if (par[x] > par[y]) swap(x, y);
  20. par[x] += par[y];
  21. par[y] = x;
  22. }
  23. }
  24. };
  25. int main() {
  26. ios_base::sync_with_stdio(false), cin.tie(0);
  27. int N;
  28. cin >> N;
  29. vector<double> x(N), y(N);
  30. for (int i = 0; i < N; ++i) cin >> x[i] >> y[i];
  31. auto calc = [&](int i, int j) -> double {
  32. return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
  33. };
  34. vector<Edge> edges;
  35. int s = N, t = N + 1;
  36. for (int i = 0; i < N; ++i) {
  37. edges.push_back(Edge(100.0 - y[i], pii(s, i)));
  38. edges.push_back(Edge(100.0 + y[i], pii(t, i)));
  39. for (int j = i + 1; j < N; ++j) {
  40. edges.push_back(Edge(calc(i, j), pii(i, j)));
  41. }
  42. }
  43. sort(edges.begin(), edges.end());
  44. UnionFind uf(N + 2);
  45. double res = 0.0;
  46. for (auto e : edges) {
  47. uf.merge(e.second.first, e.second.second);
  48. if (uf.issame(s, t)) {
  49. res = e.first / 2;
  50. break;
  51. }
  52. }
  53. cout << fixed << setprecision(10) << res << endl;
  54. return 0;
  55. }