1 条题解

  • 3
    @ 2024-6-12 19:41:38

    题意:给定一个长度为 L 的由数字 0 到 9 组成的数字串 S,我们要找出这个数字串中所有是给定正整数 p 的倍数的连续子串。这些连续子串可以通过从数字串 S 中选取不同的起始位置和结束位置得到,一共有 L(L+1)/2 个连续子串。然后计算出满足是 p 的倍数(即亲朋数)的子串的数量。并且强调了即使同一个子串在数字串中的位置不同,也要分别计数。例如数字串“12342”中“2”出现了两次且位置不同,就被计为两个不同的亲朋数。需要通过编程来解决计算亲朋数个数的问题。

    解题思路:在主函数中,首先输入 p 和数字串 S。然后通过循环不断处理数字串。

    在每次循环中,先初始化新的状态数组 st_new 为 0。根据当前字符对应的数字 d,计算各种状态的更新,也就是通过计算不同位置和数字组合后对 p 的余数情况,并更新相应状态数组的计数。当计算到某个余数为 0 时(即当前子串对应的数是 p 的倍数),就将结果 res 增加。最后将新状态数组的值赋给旧状态数组,以便在下一次循环中继续使用。最终输出的 res 就是满足条件的亲朋数的总数。

    #include <iostream>
    using namespace std;
    
    // 定义字符数组 S
    char S[1000001];
    
    // 定义两个长度为 128 的长整型数组,用于存储状态信息
    long long st_old[128];
    long long st_new[128];
    
    int main() {
        int p = 0;  // 定义变量 p,即要判断是否为倍数的那个数
    
        // 输入 p
        cin >> p;
    
        // 输入字符串 S
        cin >> S;
    
        // 初始化 st_old 数组为 0
        for (int i = 0; i < p; i++)
            st_old[i] = 0;
    
        long long res = 0;  // 用于统计亲朋数的数量
    
        // 遍历字符串 S
        for (int t = 0; S[t]!= '\0'; t++) {
            // 每次循环开始,重新初始化 st_new 数组为 0
            for (int i = 0; i < p; i++)
                st_new[i] = 0;
    
            int d = S[t] - '0';  // 获取当前字符对应的数字
    
            // 根据当前数字,更新各种可能的余数状态的计数
            for (int i = 0; i < p; i++)
                st_new[(i * 10 + d) % p] += st_old[i];
    
            st_new[d % p]++;  // 单独处理当前数字本身的余数情况
    
            // 如果当前状态下余数为 0,说明找到了一个亲朋数,增加结果计数
            res += st_new[0];
    
            // 将本次循环更新后的状态数组传递给下次循环使用
            for (int i = 0; i < p; i++)
                st_old[i] = st_new[i];
        }
    
        cout << res << endl;  // 输出亲朋数的总数
        return 0;
    }
    
    • 1

    [GESP样题 六级] 亲朋数

    信息

    ID
    657
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    12
    已通过
    7
    上传者