Featured image of post 2022 ICPC 香港站 (Gym 104172) 训练记录

2022 ICPC 香港站 (Gym 104172) 训练记录

EC-Final 2022 赛前例行训练

正式训练

K. Maximum GCD

注意到两个结论:首先,对 $n$ 任意取模的结果只可能是小于 $\dfrac{n}{2}$ 的正整数。其次,一个序列的最大公约数不会超过这个序列的最小值。

不妨设给出的序列的最小值为 $a$。如果序列没有 $[a + 1, 2a]$ 中的数,那么根据结论一,其他所有数均可以变成 $a$,而结论二表明这一结果是最大的。

序列中有 $2a$ 并不会影响上述结论,因为显然 $a$ 能整除 $2a$,不影响最大公约数。

如果序列中有 $[a + 1, 2a)$ 中的数,那么显然 $a$ 已经取不到了。如果 $a$ 是偶数,我们可以将所有 $[a + 1, 2a)$ 中的数变成 $\dfrac{a}{2}$ 来构造出一组解。如果 $a$ 是奇数,我们可以将所有 $[a, 2a)$ 中的数变成 $\dfrac{a - 1}{2}$ 来构造出一组解。

A. TreeScript

显然把一个子树建完再开新坑是最优的。然后不难发现对于每个节点 $u$,最后一个被建的子树可以复用 $u$ 的寄存器。直接 DP 即可。

L. Permutation Compression

由于每次删除的是一个区间的最大值,考虑从大到小进行贪心。每次删的时候查一下最长能用多长的区间进行删除。需要用一些数据结构维护由于删除造成的下标偏移。

 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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <bits/stdc++.h>
using namespace std;

bool solve() {
    int n, m, k;
    cin >> n >> m >> k;

    vector<int> pos(n + 1);
    for(int i = 1; i <= n; i++) {
        int val;
        cin >> val;
        pos[val] = i;
    }

    bool invalid = false;
    vector<bool> used(n + 1);
    for(int i = 1, lst = 0; i <= m; i++) {
        int val;
        cin >> val;
        if(pos[val] < lst) {
            invalid = true;
        }
        lst = pos[val];
        used[val] = true;
    }

    map<int, int> tool;
    for(int i = 1; i <= k; i++) {
        int val;
        cin >> val;
        tool[val]++;
    }

    if(invalid) {
        return false;
    }

    set<int> used_position {0, n + 1};
    vector<int> bit(n + 1);

    auto query = [&] (int u) {
        int ans = 0;
        while(u > 0) {
            ans += bit[u];
            u -= u & -u;
        }
        return ans;
    };

    for(int i = n; i >= 1; i--) {
        if(used[i]) {
            used_position.insert(pos[i]);
            continue;
        }
        int cur_pos = pos[i];
        auto nxt = used_position.lower_bound(pos[i]);
        auto pre = prev(nxt);

        int mxlen = *nxt - *pre - 1 - (query(*nxt - 1) - query(*pre));
        auto it = tool.upper_bound(mxlen);
        if(it == tool.begin()) {
            return false;
        }
        it--;
        if(--(it->second) == 0) {
            tool.erase(it);
        }

        while(cur_pos <= n) {
            bit[cur_pos]++;
            cur_pos += cur_pos & -cur_pos;
        }
    }
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while(t--) {
        if(solve()) {
            puts("YES");
        } else {
            puts("NO");
        }
    }

    return 0;
}

F. Sum of Numbers

可以发现切出来相邻的两端长度之差不能超过 $1$。暴力枚举即可。

赛时这题的代码是队友写的,赛后感觉实现的不是很精细就自己重写了一个版本。

  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
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <bits/stdc++.h>
using namespace std;

struct BigInt {
    static const int MOD = 1000000000;
    static const int N_BIT = 9;
    vector<int> nums;

    BigInt(const char *s, int n) {
        int val = 0, base = 1;
        for(int i = n - 1; i >= 0; i--) {
            val += (s[i] - '0') * base;
            base *= 10;
            if(base == MOD) {
                nums.push_back(val);
                val = 0;
                base = 1;
            }
        }
        if(nums.empty() || val != 0) {
            nums.push_back(val);
        }
    }

    BigInt &operator= (const BigInt &&u) {
        nums = move(u.nums);
        return *this;
    }

    BigInt &operator+= (const BigInt &u) {
        nums.resize(max(nums.size(), u.nums.size()));
        int carry = 0;
        for(size_t i = 0; i < nums.size(); i++) {
            nums[i] += carry + (i < u.nums.size() ? u.nums[i] : 0);
            if(nums[i] >= MOD) {
                nums[i] -= MOD;
                carry = 1;
            } else {
                carry = 0;
            }
        }
        if(carry) {
            nums.push_back(carry);
        }
        return *this;
    }

    bool operator< (const BigInt &u) {
        if(nums.size() != u.nums.size()) {
            return nums.size() < u.nums.size();
        }
        for(size_t i = nums.size() - 1; i < nums.size(); i--) {
            if(nums[i] != u.nums[i]) {
                return nums[i] < u.nums[i];
            }
        }
        return false;
    }
};

ostream& operator<< (ostream &os, const BigInt &u) {
    ios states(nullptr);
    states.copyfmt(os);

    os << u.nums.back();
    for(int i = (int)u.nums.size() - 2; i >= 0; i--) {
        os << setw(BigInt::N_BIT) << setfill('0') << u.nums[i];
    }

    os.copyfmt(states);
    return os;
}

void solve() {
    int n, k;
    string str;
    cin >> n >> k >> str;

    vector<int> lths(k + 1);
    BigInt ans(str.c_str(), n);

    function<void(int)> dfs = [&] (int idx) {
        if(idx > k) {
            partial_sum(lths.begin(), lths.end(), lths.begin());

            int base = accumulate(lths.begin(), lths.end(), 0);
            if((n - base) % (k + 1) == 0) {
                base = (n - base) / (k + 1);
                if(base + *min_element(lths.begin(), lths.end()) > 0) {
                    BigInt res(nullptr, 0);
                    int l = 0;
                    for(int cur : lths) {
                        res += BigInt(str.c_str() + l, base + cur);
                        l += base + cur;
                    }
                    if(res < ans) {
                        ans = move(res);
                    }
                }
            }

            adjacent_difference(lths.begin(), lths.end(), lths.begin());
            return;
        }
        
        for(int i = -1; i <= 1; i++) {
            lths[idx] = i;
            dfs(idx + 1);
        }
    };

    dfs(1);
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}

补题记录

EH 题队友在训练的时候解决了。剩下的题暂咕。

Licensed under CC BY-NC-SA 4.0
最后更新于 Feb 16, 2023
ぶちまけちゃおうか 星に!
Built with Hugo
主题 StackJimmy 设计