第二十一届浙大宁波理工学院程序设计大赛(同步赛)题解

比赛链接

A. Qfish的魔方

Solution

把输入的 9 9 9 个数排序,然后 3 3 3 3 3 3 个地逐行放进一共 3 × 3 3 \times 3 3×3 的二维数组里,最后根据题意判断即可。

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
    
    std::array<int, 9> a{
   };
    for (int i = 0; i < 9; i++) {
   
        std::cin >> a[i];
    }
    std::ranges::sort(a);

    std::array<std::array<int, 3>, 3> g{
   };
    for (int i = 0; i < 3; i++) {
   
        for (int j = 0; j < 3; j++) {
   
            g[i][j] = a[i * 3 + j];
        }
    }
    for (int i = 0; i < 3; i++) {
   
        if (std::count(g[i].begin(), g[i].end(), g[i][0]) != 3) {
   
            std::cout << "No\n";
            return 0;
        }
        if (i + 1 < 3) {
   
            for (int j = 0; j < 3; j++) {
   
                if (g[i + 1][j] <= g[i][j]) {
   
                    std::cout << "No\n";
                    return 0;
                }
            }
        }
    }
    std::cout << "Yes\n";
    
    return 0;
}

B. 寻找最大值

Solutioin

按照题意模拟交换字符即可。

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

void solve() {
   
    int N;
    std::cin >> N;

    std::string S;
    std::cin >> S;

    i64 ans = std::stoll(S);
    for (int i = 0; i < N; i++) {
   
        for (int j = i + 1; j < N; j++) {
   
            std::swap(S[i], S[j]);
            ans = std::max<i64>(ans, std::stoll(S));
            std::swap(S[i], S[j]);
        }
    }
    std::cout << ans << "\n";
}

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
    
    int T = 1;
    std::cin >> T;
    
    while (T--) {
   
        solve();
    }
    
    return 0;
}

C. 找数字

Solution

同样是按照题意模拟,记录每个数的出现次数。

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
    
    int n;
    std::cin >> n;

    std::map<int, int> cnt;
    for (int i = 0; i < n; i++) {
   
        int x;
        std::cin >> x;
        cnt[x]++;
    }

    int tot = 0;
    for (const auto &[k, v]: cnt) {
   
        if (v == 1) {
   
            std::cout << k << " \n"[++tot == 2];
        }
    }
    
    return 0;
}

D. 找更多的数字

题目大意

给定一个长度为 n n n 的数组 a a a,现在有 q q q 次询问。
每次询问,给定 l ,   r l, \ r l, r,对于子数组 a [ l . . . r ] a[l...r] a[l...r],保证其中有 2 2 2 个只出现 1 1 1 次的数字,其他数字都出现了 2 2 2 次。
请你找到这 2 2 2 个只出现 1 1 1 次的数,从小到大输出。

数据范围

  • 1 ⩽ n ⩽ 1 0 5 1 \leqslant n \leqslant 10^5 1n105
  • 0 ⩽ a i ⩽ 1 0 6 0 \leqslant a_i \leqslant 10^6 0ai106
  • 1 ⩽ q ⩽ 1 0 6 1 \leqslant q \leqslant 10^6 1q106
  • 1 ⩽ l < r ⩽ n 1 \leqslant l < r \leqslant n 1l<rn,且保证 [ l ,   r ] [l, \ r] [l, r] 内满足仅有 2 2 2 个数出现 1 1 1 次,其余均出现 2 2 2 次。

Solution

不妨设那 2 2 2 个特殊的数是 x ,   y x, \ y x, y
由题意可得,对于给定区间 [ l ,   r ] [l, \ r] [l, r] 的前缀异或和,得到的结果一定是 x ⊕ y x \oplus y xy x ,   y x, \ y x, y 都是只出现一次)。

考虑用 x ⊕ y x \oplus y xy 的某一位为 1 1 1 的二进制位,来找到 x x x 或者 y y y。不妨设这一位是第 k k k 位。

对于前缀异或和,可以考虑其变种:
拆位前缀异或和,即对每一位都开一个前缀和数组,且仅考虑每一位为 1 的时候将数异或上去。

这样的话对于给定区间 [ l ,   r ] [l, \ r] [l, r],由于限制了其余数均出现 2 2 2 次,所以不论第 k k k 位上其余数是什么,整段区间(除了 x ,   y x, \ y x, y)在这一位上的前缀异或和都是 0 0 0,又因为 x x x y y y 只有一个数在第 k k k 位是 1 1 1(它们的异或值 x ⊕ y x \oplus y xy 在第 k k k 位是 1 1 1,所以最后会得到 x x x 或者 y y y

时间复杂度 O ( 20 n ) \mathcal{O}(20n) O(20n)

C++ Code

#include <bits/stdc++.h>

using i64 = long long;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n, q;
    std::cin >> n >> q;

    std::vector<int> a(n);
    for (int i = 0; i < n; i++) {
   
        std::cin >> a[i];
    }

    std::vector<int> s(n + 1);
    std::vector<std::array<int, 20>> xs(n + 1);
    for (int i = 0; i < n; i++) {
   
        s[i + 1] = s[i] ^ a[i];
        for (int j = 0; j < 20; j++) {
   
            xs[i + 1][j] = xs[i][j] ^ ((a[i] >> j & 1) * a[i]);
        }
    }

    while (q--) {
   
        int l, r;
        std::cin >> l >> r;
        l--;

        int v = s[r] ^ s[l];
        for (int i = 0; i < 20; i++) {
   
            if (v >> i & 1) {
   
                int x = xs[r][i] ^ xs[l][i];
                int y = x ^ v;
                if (x > y) {
   
                    std::swap(x, y);
                }
                std::cout << x << " " << y << "\n";
                break;
            }
        }
    }
    
    return 0;
}

E. 井字棋

Solution

同样是按题意模拟,判断每列、每行、对角线、反对角线

C++ Code

#include <bits/stdc++.h>

using i64 = int64_t;
using u64 = uint64_t;
using f64 = double_t;
using i128 = __int128_t;

int main() {
   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cout << std::fixed << std::setprecision(12);
    
    std::array<std::string, 3> g{
   };
    for (int i = 0; i < 3; i++) {
   
        std::cin >> g[i];
    }

    auto check = [&](char c) {
   
        if (g[0][0] == c and g[0][0] == g[1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值