2023ICPC台湾网络赛VP记录

solved 7 problems

A、B、E、H、J、K、L:dbywsc

前言

第一次做台湾赛区的题目,被雷到了,深刻怀疑出题人的水平和态度。

补题链接

官方题解

K.kick

题意

给定一个字符串 \(s\) ,求其中子串 "kick" 的数量。

思路

直接遍历一遍即可。

代码

void solve(void) {
    std::string s;
    std::cin >> s;
    int cnt = 0;
    for(int i = 0; i < s.size() - 3; i++) 
        if(s[i] == 'k' && s[i + 1] == 'i' && s[i + 2] == 'c' && s[i + 3] == 'k') cnt++;
    std::cout << cnt;
}

J.Java Warriors

题意 && 思路

输出 \(n \times 4000\)

代码

void solve(void) {
    int n; std::cin >> n;
    std::cout << n * 4000;
}

A.Advance to Taoyuan Regional

题意

给定一个日期,判断当前日期和 \(2023\)\(10\)\(21\) 日之间是否至少相隔 \(35\) 天。

思路

直接判断当前日期是否在 “2023-09-16” 之前即可。

代码

void solve(void) {
    std::string s; std::cin >> s;
    if(s > "2023-09-16") {
        std::cout << "TOO LATE";
        return;
    }
    std::cout << "GOOD";
}

L.Location, Location, Location

题意

给定二维平面上的 \(n\) 个点,要求找到一个点,使得这 \(n\) 个点到这个点的哈夫曼距离的总和最小。如果存在多个,取 \(x\) 最小的点。

思路

要想让哈夫曼距离的总和最小,应该将 \(x\) 轴和 \(y\) 轴分开看,取 \(n\) 个点 \(x\) 坐标的中位数和 \(y\) 坐标的中位数构成一个点即可。

代码

void solve(void) {
    int n; std::cin >> n;
    std::vector<int> x(n + 1), y(n + 1);
    for(int i = 1; i <= n; i++)
        std::cin >> x[i] >> y[i];
    std::sort(x.begin() + 1, x.end());
    std::sort(y.begin() + 1, y.end());
    if(n % 2) {
        std::cout << x[(n + 1) / 2] << " " << y[(n + 1) / 2];
    }
    else std::cout << x[n / 2] << ' ' << y[n / 2];
}

B.Better Chance

题意

我个人认为这是本场中出的最烂的一个题,题意含糊不清,题目描述中没有给出任何关键信息,将有用的信息塞在冗杂的 Note 中,强行让人阅读理解。

其实就是给定了一个公式

\[Rank = (R - 1) / S \]

分别给一个队伍在两场比赛中的 \(R\)\(S\) ,问在哪一场中计算出的排名更高。

思路

位了避免精度问题,可以将式子变形:

\[\frac{R_t - 1}{S_t} < \frac{R_J - 1}{S_J}\rightarrow (R_t - 1)S_J < (R_J - 1)S_T \]

将除法变成乘法。此时还需要考虑 \(S_T,S_J\) 是小数,由于题目上说它们乘以一百一定是整数,因此可以将它们统一乘上 \(100\) 。但是要注意本题卡了 \(C++\) 等语言小数舍入的规则,必须使用 std::round() 将小数舍入改为四舍五入的形式。

代码

void solve(void) {
    int a, b;
    double c, d;
    std::cin >> a >> b >> c >> d;
    i64 rk1 = (a - 1) * (i64)std::llround(d * 100.0);
    i64 rk2 = (b - 1) * (i64)std::llround(c * 100.0);
    if(rk1 == rk2) std::cout << "SAME";
    else std::cout << (rk1 < rk2 ? "TAOYUAN" : "JAKARTA");
}

E.Exponentiation

题意

给定 \(x + x^{-1} = \alpha\) ,求 \(x^{\beta} + x^{-\beta} \mod m\) 的值。

思路

这是一个比较经典的式子,设 \(T_n = x^{n} + x^{n}\) ,注意到:

\(T_0 = 2\)
\(T_1 = \alpha\)
\(T_n = \alpha \ T_{n - 1} - T_{n - 2}\)

因此可以构造出矩阵:

\[\begin{bmatrix} T_n \\ T_{n - 1} \end{bmatrix} = \begin{bmatrix} \alpha & -1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} T_{n - 1} \\ T_{n - 2} \end{bmatrix}\]

使用矩阵快速幂加速即可。

需要注意本题卡了 __uint128_t ,对C++非常不友好,所以用了Python代码。

代码

import sys

def mul(x, y, m):
    a = (x[0] * y[0] % m + x[1] * y[2] % m) % m
    b = (x[0] * y[1] % m + x[1] * y[3] % m) % m
    c = (x[2] * y[0] % m + x[3] * y[2] % m) % m
    d = (x[2] * y[1] % m + x[3] * y[3] % m) % m
    return (a, b, c, d)

def pow_mat(base, exp, m):
    res = (1, 0, 0, 1)
    while exp > 0:
        if exp % 2 == 1:
            res = mul(res, base, m)
        base = mul(base, base, m)
        exp >>= 1
    return res

def solve():
    input = sys.stdin.read().split()
    a = int(input[0])
    b = int(input[1])
    m = int(input[2])
    
    if b == 0:
        print(2 % m)
        return
    if b == 1:
        print(a % m)
        return
    
    M = (a, (m - 1) % m, 1, 0)
    P = pow_mat(M, b - 1, m)
    ans = (P[0] * a % m + P[1] * 2 % m) % m
    print(ans)

if __name__ == "__main__":
    solve()

H.Heap Structure

题意

给定一个大小为 \(n\) ,二叉树形式的,每个元素互不相同的最小堆,问第 \(k\) 小第元素最多可以放在几个不同的位置上。

思路

设第 \(k\) 小元素所在的子树大小为 \(s(i)\) ,在整个堆中,有 \(n - k\) 个元素大于当前元素,显然它的子树中的其他 \(s(i) - 1\) 个元素一定是由这 \(n - k\) 个元素组成的,也就是说我们需要满足 \(s(i) - 1 \leq n - k\) 。当某一层的节点满足这个要求时,它下面的节点一定也满足这个要求,因此可以二分。

代码

void solve(void) {
    u64 n, k; std::cin >> n >> k;
    auto check = [&](i64 x) -> bool {
        u64 left = x, right = x, cnt = 0;
        while(left <= n) {
            u64 r = (right < n ? right : n);
            cnt += r - left + 1;
            left <<= 1;
            right = (right << 1) | 1;
        }
        return cnt <= n - k + 1;
    };
    u64 ub = 0;
    if(k >= 64) {
        ub = n;
    } else {
        u64 t = 1ull << k;
        ub = std::min(n, t - 1);
    }
    u64 l = 1, r = ub, ans = ub + 1;
    while(l <= r) {
        u64 mid = (l + r) / 2;
        if(check(mid)) {
            r = mid - 1;
            ans = mid;
        } else l = mid + 1;
    }
    std::cout << (ans <= ub ? (ub - ans + 1) : 0);
}
posted @ 2025-08-18 01:48  dbywsc  阅读(27)  评论(0)    收藏  举报