Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • codeforses 题解

  • atcoder 题解

  • XCPC 题解

  • 校训练赛题解

    • 【2024暑#108】ACM暑期第三次测验(个人赛)题解
    • 【2024暑#109】ACM暑期第四次测验(个人赛)题解
    • 【2024暑#110】ACM暑期第五次测验(个人赛)题解
      • A - 快速幂
        • Solution
        • Code
      • B - 存钱
        • Solution
      • C - Imbalanced XiaoMo
        • Question
        • Solution #1
        • Code #1
        • Solution #2
        • Code #2
      • D - dijikstra
        • Solution
        • Code
      • E - 约数最大值
        • Solution
    • 【2025秋120】ACM周测(个人赛,div3)题解
    • Sakura Tears training 4 题解
    • Sakura Tears training 5 题解
  • 牛客题解

  • 蓝桥杯题解

  • 典题选讲

  • 杂题

  • 算法题解
  • 校训练赛题解
martian148
2024-08-18
目录

【2024暑#110】ACM暑期第五次测验(个人赛)题解

# A - 快速幂

# Solution

由于 pow(A,B)pow(A,B)pow(A,B) 非常大,无法直接计算。我们如何在不实际计算它们的情况下进行比较?

首先,我们将找到 pow(A,C)pow(A,C)pow(A,C) 的符号。如果 AAA 为负且 CCC 为奇数,则它为负数;否则为非负数

如果 pow(A,C)pow(A,C)pow(A,C) 和 pow(B,C)pow(B,C)pow(B,C) 的符号相同,直接比较 ∣A∣|A|∣A∣ 和 ∣B∣|B|∣B∣ 即可

# Code

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

int main(){
    int a, b, c; cin >> a >> b >> c;
    if (c % 2 == 0)
        cout << (abs(a) < abs(b) ? "<" : abs(a) == abs(b) ? "=" : ">") << endl;
    else
        cout << (a > b ? ">" : a == b ? "=" : "<") << endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

# B - 存钱

# Solution

签到题,直接模拟即可

# C - Imbalanced XiaoMo

# Question

给出一个序列 aia_iai​,需要在 aia_iai​ 中插入一个数 xxx,使得 ai−ai−1(2≤i≤n)a_i-a_{i-1}(2\le i\le n)ai​−ai−1​(2≤i≤n) 的最大值最小,其中 xxx 是序列 {d}\{d\}{d} 和 {f}\{f\}{f} 中各取一个数的加和

# Solution #1

我们想要最小化最大值,那么肯定需要把最大的间隙缩小,如果最大的间隙有两个,那么最大的间隙就是答案,否则能缩小最大间隙

思考怎样缩小最大间隙才能使得最大值最小,肯定是对半分最小的间隙,假设 mid=(ai+ai−1)/2mid=(a_i+a_{i-1})/2mid=(ai​+ai−1​)/2,则需要,找到最接近的 midmidmid 的 fj+dkf_j+d_kfj​+dk​

这是一个经典问题,我们可以用二分或者双指针解决

# Code #1

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int INF = 1e18;
void solve() {
    int n, m, k; cin >> n >> m >> k;
    vector<int> a(n + 1), d(m + 1), f(k + 1, 0);
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) cin >> d[i];
    for (int i = 1; i <= k; i++) cin >> f[i];
    pii mx1 = {-1,0}, mx2 = {-1,0};
    for (int i = 1; i < n; i++) {
        int x = a[i + 1] - a[i];
        if (x > mx1.first) { mx2 = mx1; mx1 = {x, i}; }
        else if (x > mx2.first) { mx2 = {x, i}; }
    }
    if (mx1.first == mx2.first) {
        cout << mx1.first << '\n';
        return ;
    }
    // 把 pos1 的位置拆开
    int mid = (a[mx1.second] + a[mx1.second + 1]) / 2;
    sort (d.begin() + 1, d.end());
    sort (f.begin() + 1, f.end());
    int ret = mx1.first;
    for (int i = 1; i <= m; i++) {

        auto check = [&](int pos) {
            if (pos < 1 || pos > k) return INF;
            int x = d[i] + f[pos];
            if (!(x > a[mx1.second] && x < a[mx1.second + 1])) return INF;
            return max (x - a[mx1.second], a[mx1.second + 1] - x);
        };

        int pos = lower_bound(f.begin() + 1, f.end(), mid - d[i]) - f.begin();
        ret = min (ret, check(pos));
        ret = min (ret, check(pos - 1));
        ret = min (ret, check(pos + 1));
    }
    cout << max (mx2.first, ret) << '\n';
}

signed main() {
    int t; cin >> t;
    while (t--) solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# Solution #2

“使得最大值最小”是一个经典的二分答案模型,我们计算出在一个题都不添加的情况下的不平衡性 sss,二分最终答案的范围为 1≤ans≤s1 \leq ans \leq s1≤ans≤s。

问题就变成了能否通过添加一道题使得最终的不平衡性小于等于 xxx。考虑所有的 2≤i≤n2 \leq i \leq n2≤i≤n 且 ai−ai−1>xa_i - a_{i-1} > xai​−ai−1​>x。如果这样的 iii 有大于 1 个,显然添加一个题目无法使得最终的不平衡性减少到 xxx 及以下。如果没有这样的 iii,显然一定可以的。难点就在于这样的 iii 恰好有一个。

如果对于这个 iii,有 ai−ai−1>2xa_i - a_{i-1} > 2xai​−ai−1​>2x,那么就算恰好能够添加一道题使得它的难度在这段区间的正中间,最终的不平衡性也是大于 xxx 的,直接 pass 掉。否则,我们就需要判断是否能找到一对 uuu 和 v(1≤u≤m且1≤v≤k)v (1 \leq u \leq m 且 1 \leq v \leq k)v(1≤u≤m且1≤v≤k) 使得 ai−x≤du+fv≤ai−1+xa_i - x \leq d_u + f_v \leq a_{i-1} + xai​−x≤du​+fv​≤ai−1​+x。我们可以枚举 uuu,在二分出最小的大于等于 ai−xa_i - xai​−x 的 du+fvd_u + f_vdu​+fv​ 是否小于等于 ai−1+xa_{i-1} + xai−1​+x。若能有一个 uuu 使得该问题的答案为“是”,显然就是可以的,如果“一个”都没有就不行。

# Code #2

#include <bits/stdc++.h>
#define N 110000
#define M 220000
#define K 220000
#define int long long
using namespace std;

int t, n, m, k, a[N], d[M], f[K];

bool judge(int x);

signed main() {
    scanf("%lld", &t);
    while (t--) {
        scanf("%lld%lld%lld", &n, &m, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= m; i++) scanf("%d", &d[i]);
        sort(d + 1, d + 1 + m);
        for (int i = 1; i <= k; i++) scanf("%d", &f[i]);
        sort(f + 1, f + 1 + k);
        
        int s = 0;
        for (int i = 2; i <= n; i++) 
            s = max(s, a[i] - a[i - 1]);
        
        int l = 0, r = s + 1;
        while (l + 1 < r) {
            int mid = (l + r) / 2;
            if (judge(mid) == false)
                l = mid;
            else
                r = mid;
        }
        printf("%lld\n", r);
    }
    return 0;
}

bool judge(int x) {
    int id = 0;
    for (int i = 2; i <= n; i++) {
        if (a[i] - a[i - 1] > x) {
            if (id != 0) 
                return false;
            else 
                id = i;
        }
    }
    if (id == 0) 
        return true;
    if (a[id] - a[id - 1] > 2 * x) 
        return false;
    
    int mbl = a[id] - x, mbr = a[id - 1] + x;
    bool flag = false;
    
    for (int i = 1; i <= m; i++) {
        int l = 0, r = k + 1;
        while (l + 1 < r) {
            int mid = (l + r) / 2;
            if (d[i] + f[mid] < mbl)
                l = mid;
            else
                r = mid;
        }
        if (l != k && d[i] + f[l + 1] <= mbr) {
            flag = true;
            break;
        }
    }
    return flag;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# D - dijikstra

# Solution

由于边权都相同,考虑使用 bfs 得到最短路

我们在 bfs 时,需要记录下两个值:起点到 iii 的最短路 ddd 和 走到 ddd 的方案数 ccc

对于 iii 的下一个节点 jjj 如果满足 di+1=djd_i+1=d_jdi​+1=dj​ 则,i→ji\rightarrow ji→j 是一条走到 jjj 的最短路,所以 cj=cj+cic_j=c_j+c_icj​=cj​+ci​

# Code

#include <bits/stdc++.h>
using namespace std;
constexpr int TT = 100003;
using pii = pair<int, int>;

int main() {
    ios::sync_with_stdio(0);
    int n, m; cin >> n >> m;
    vector<vector<int>> g(n + 1);
    for (int i = 0; i < m; i++) {
        int a, b; cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    vector<int> vis(n + 1, 0);
    vector<pii> dis(n + 1, {0, 0});
    queue<int> q;
    vis[1] = 1;  q.push(1); dis[1] = {0, 1};

    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : g[u]) {
            if (!vis[v]) {
                vis[v] = 1;
                auto [d, c] = dis[u];
                auto &[d_, c_] = dis[v];
                d_ = d + 1; c_ = c;
                q.push(v);
            }
            else {
                auto [d, c] = dis[u];
                auto &[d_, c_] = dis[v];
                if (d + 1 == d_) c_ = (c_ + c) % TT;
            }
        }
    }

    for (int i = 1; i <= n; i++) 
       cout << dis[i].second << '\n';

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# E - 约数最大值

# Solution

有点类似于 PTA 题,for 循环枚举 [l,r][l,r][l,r] 之间的所有数 xxx,然后使用 O(x)O(\sqrt{x})O(x​) 的复杂度来找约数个数,总时间复杂度为 O((r−l)x)O((r-l)\sqrt{x})O((r−l)x​)

上次更新: 2025/04/08, 18:03:31
【2024暑#109】ACM暑期第四次测验(个人赛)题解
【2025秋120】ACM周测(个人赛,div3)题解

← 【2024暑#109】ACM暑期第四次测验(个人赛)题解 【2025秋120】ACM周测(个人赛,div3)题解→

最近更新
01
Java基础语法
05-26
02
开发环境配置
05-26
03
pink 老师 JavaScript 学习笔记
05-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式