• CSDN 编程竞赛第五期题解


    总览

    退役竞赛选手出来混个存在感,比赛链接,似乎 CSDN 要做成周赛了。

    题目难度上比较简单,部分是原题,需要注意些细节。

    赛途不允许切出屏幕和使用通讯软件,整体比较像笔试,偏向于考察应试技能,那么有原题也说得过去。

    赛前出现长时间无法进入的情况,赛中编辑器和自助评测使用体验较差,例如代码模板对用户不友好(函数参数不一致、头文件配置不灵活等)、语法补全提示相关度忽高忽低、评测结果没有剔除 stderr 等。同天还有力扣周赛和百度之星初赛,它们所在平台在编辑和评测上的用户体验就好些。

    题目分析

    1. 寻因找祖

    题意:求约数个数为 n n n 的最小正整数 x x x n ≤ 1000 n \leq 1000 n1000

    思路:(比较古老的原题,加强版见 SGU 473

    • x = ∏ i = 1 t p i e i x = \prod_{i = 1}^{t}{{p_i}^{e_i}} x=i=1tpiei ( p i < p i + 1 , p i  is prime ) (p_i < p_{i + 1}, p_i\text{ is prime}) (pi<pi+1,pi is prime),则它的约数个数 σ ( x ) = ∏ i = 1 t ( e i + 1 ) \sigma(x) = \prod_{i = 1}^{t}{(e_i + 1)} σ(x)=i=1t(ei+1),因此 e i e_i ei 的范围被限制在 ( e i + 1 ) ∣ n (e_i + 1) | n (ei+1)n
    • 如果两个数字的 { e i } \{e_i\} {ei} 集合一样,那么它们的约数个数相同。
      • 对于一个固定的 { e i } \{e_i\} {ei} 集合,考虑其对应的数字 x x x,如果存在 e i < e i + 1 e_i < e_{i + 1} ei<ei+1,那么可以构造出一个更小的数字 x ′ = ∏ i = 1 t p i e ′ i x' = \prod_{i = 1}^{t}{{p_i}^{{e'}_i}} x=i=1tpiei 对应该集合,这里 e ′ i = e i + 1 {e'}_i = e_{i + 1} ei=ei+1, e ′ i + 1 = e i {e'}_{i + 1} = e_i ei+1=ei
      • 对于一个固定的 { e i } \{e_i\} {ei} 集合,最小的正整数 x x x 一定只用到最小的 t t t 个质数,且 e i ≥ e i + 1 e_i \geq e_{i + 1} eiei+1,否则总能通过调整得到更小的正整数 x x x
    • 接下来可以暴力搜索(可以手动验证状态不多)或者 DP,但考虑到 n  is prime n\text{ is prime} n is prime 时答案可能非常大(例如 2 996 2^{996} 2996),不如直接暴力搜索。

    代码:Python3

    class Solution:
        def __init__(self) -> None:
            self.pr = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
            self.ans = 1
    
        def dfs(self, dep, cur, rem, upp):
            if rem == 1:
                self.ans = min(self.ans, cur)
                return
            if dep >= len(self.pr):
                return
            for i in range(1, upp + 1):
                if i * i > rem:
                    break
                if rem % i > 0:
                    continue
                if i > 1:
                    self.dfs(dep + 1, cur * (self.pr[dep] ** (i - 1)), rem // i, i)
                j = rem // i
                if i < j:  # j > 1
                    self.dfs(dep + 1, cur * (self.pr[dep] ** (j - 1)), rem // j, j)
    
        def solution(self, n):
            self.ans = 10 ** 1000
            self.dfs(0, 1, n, n)
            return self.ans
    
    • 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

    2. 通货膨胀-x国货币

    题意:构造一个最长的正整数序列 A = [ a 1 , a 2 , … , a m ] A = [a_1, a_2, \ldots, a_m] A=[a1,a2,,am],使得 a 1 = n a_1 = n a1=n, a i + 1 ∣ a i a_{i + 1} | a_i ai+1ai,输出 m m m 的最大值。数据范围好像是 n ≤ 1 0 9 n \leq 10^9 n109

    思路:(比较古老的原题)

    • 贪心构造即可,使每个 a i a i + 1 \frac{a_i}{a_{i + 1}} ai+1ai 为质数不会使解更差。令 n = ∏ i = 1 t p i e i n = \prod_{i = 1}^{t}{{p_i}^{e_i}} n=i=1tpiei ( p i < p i + 1 , p i  is prime ) (p_i < p_{i + 1}, p_i\text{ is prime}) (pi<pi+1,pi is prime),则答案为 1 + ∑ i = 1 t e i 1 + \sum_{i = 1}^{t}{e_i} 1+i=1tei

    代码:C++

    int solution(int n) {
        typedef long long LL;
        int result = 1;
        for(int i = 2; i <= n; ++i) {
            if((LL)i * i > n)
                i = n;
            for( ; n % i == 0; n /= i, ++result);
        }
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3. 莫名其妙的键盘

    题意:初始有一个空串 S S S,每次操作可以向其末尾增加一个小写字母,如果增加的字符是元音字符,则在增加后需要将 S S S 反转,然后才视为此次操作结束。给定目标串 T T T,问有多少种操作方案能使 S S S 在操作结束后变成 T T T。数据范围好像是 ∣ T ∣ ≤ 100 |T| \leq 100 T100

    思路:

    • S S S 在任意时刻必须是 T T T T T T 的反转串的一个区间,那么记录 S S S 变成每个区间的方案即可 DP 出最终答案,时间复杂度 O ( ∣ T ∣ 2 ) \mathcal{O}(|T|^2) O(T2)

    代码:C++

    #include 
    using namespace std;
    int solution(std::string str){
        int n = str.size();
        vector<bool> sp(n);
        vector<vector<pair<int, int> > > dp(n, vector<pair<int, int> >(n));
        for(int i = 0; i < n; ++i) {
            dp[i][i] = {1, 1};
            char ch = str[i];
            sp[i] = ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u';
        }
        for(int len = 2; len <= n; ++len)
            for(int L = 0, R = len - 1; R < n; ++L, ++R) {
                if(sp[L]) {
                    dp[L][R].first += dp[L + 1][R].second;
                } else {
                    dp[L][R].second += dp[L + 1][R].second;
                }
                if(sp[R]) {
                    dp[L][R].second += dp[L][R - 1].first;
                } else {
                    dp[L][R].first += dp[L][R - 1].first;
                }
            }
        return dp[0][n - 1].first;
    }
    
    • 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

    4. 三而竭

    题意:给定正整数 n n n k k k,求最小的正整数 x x x 使得 ∑ i ≥ 0 ⌊ x k i ⌋ ≥ n \sum_{i \geq 0}{\left\lfloor\frac{x}{k^i}\right\rfloor} \geq n i0kixn。数据范围好像是 n ≤ 1 0 9 n \leq 10^9 n109, 2 ≤ k ≤ 10 2 \leq k \leq 10 2k10

    思路:(比较古老的原题)

    • 函数 f ( x ) = ∑ i ≥ 0 ⌊ x k i ⌋ f(x) = \sum_{i \geq 0}{\left\lfloor\frac{x}{k^i}\right\rfloor} f(x)=i0kix 单调递增,且 f ( n ) ≥ n f(n) \geq n f(n)n,二分即可,时间复杂度 O ( log ⁡ k n log ⁡ 2 n ) \mathcal{O}(\log_k{n} \log_2{n}) O(logknlog2n)
    • 也可以做到 O ( log ⁡ k n ) \mathcal{O}(\log_k{n}) O(logkn),留给读者自行探索。感兴趣可以来做下我出的题目 「LibreOJ β Round #5」最小倍数,提交的代码是公开的。

    代码:C++

    int solution(std::vector<int>& vec){
        int n = vec[0], k = vec[1];
        int L = 1, R = n;
        while(L < R) {
            int M = (L + R) >> 1;
            int ctr = 0, rem = M;
            for( ; ctr < n && rem > 0; ctr += rem, rem /= k);
            if(ctr < n) {
                L = M + 1;
            } else {
                R = M;
            }
        }
        return L;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    后续

    别看了哪有下期啊。

  • 相关阅读:
    3.0 设计模式汇总
    能带你起飞的【数据结构】成王第十二篇:堆2
    Zookeeper Watcher机制--数据变更通知
    Java的数组使用
    Vue Admin Template关闭eslint校验,lintOnSave:false设置无效解决办法
    C++ std::tr1::function和std::tr1::bind模板类介绍,qt测试
    依赖项的处理与层的创建与注册
    32.哀家要长脑子了!
    Protocol Buffers入门
    设计模式2、抽象工厂模式 Abstract Factory
  • 原文地址:https://blog.csdn.net/skywalkert/article/details/126692523