1 条题解

  • -3
    @ 2020-07-15 10:55:22
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <list>
    #include <vector>
    #include <string>
    #include <unordered_map>
    #include <unordered_set>
    
    using namespace std;
    // 有n个正整数排成一行。你的目的是要从中取出一个或连续的若干个数,使它们的和能够被k整除。
    // 例如,有6个正整数,它们依次为1、2、6、3、7、4。若k=3,则你可以取出1、2、6,或者2、6、3、7,也可以仅仅取出一个6或者3使你所取的数之和能被3整除。
    // 当然,满足要求的取法不止以上这4种。事实上,一共有7种取法满足要求。
    // 给定n和k,以及这n个数。你的任务就是确定,从这n个数中取出其中一个数或者若干连续的数使它们的和能被k整除有多少方法。
    // 由于取法可能很多,因此你只需要输出它mod 1234567的值即可。
    
    class Solution_0
    {
        // 普通枚举算法
    public:
        void solution()
        {
            int size = 0, k = 0;
            cin >> size >> k;
            vector<int> nums(size);
            int count = 0;
            for (int i = 0; i < size; i++)
            {
                cin >> nums[i];
            }
            for (int i = 0; i < size; i++)
            {
                int sum = 0;
                for (int j = i; j < size; j++)
                {
                    sum += nums[j];
                    if (sum % k == 0)
                    {
                        count = (count + 1) % 1234567;
                    }
                }
            }
            cout << count << endl;
        }
    };
    class Solution_1
    {
        // 基于动态规划的暴力算法
    public:
        void solution()
        {
            int size = 0, k = 0;
            cin >> size >> k;
            vector<int> dp(size, 0);
            int count = 0;
            for (int i = 0; i < size; i++)
            {
                int t = 0;
                cin >> t;
                for (int j = 0; j <= i; j++)
                {
                    dp[j] = dp[j] + t;
                    if (dp[j] % k == 0)
                        count = (count + 1) % 1234567;
                }
            }
            // vector<vector<int>> dp(size, vector<int>(size, 0));
            // int count = 0;
            // for (int i = 0; i < size; i++)
            // {
            //     cin >> dp[i][i];
            //     if (dp[i][i] % k == 0)
            //     {
            //         count = (count + 1) % 1234567;
            //     }
            //     for (int j = 0; j < i; j++)
            //     {
            //         dp[j][i] = dp[j][i - 1] + dp[i][i];
            //         if (dp[j][i] % k == 0)
            //         {
            //             count = (count + 1) % 1234567;
            //         }
            //     }
            // }
            cout << count << endl;
        }
    };
    class Solution
    {
        // 基于前缀数组和的算法
        // 举个例子,假如输入的size = 6, k = 3, 数组如下
        // nums = {1, 2, 6, 3, 7, 4};
        // 前缀数组A[i]和定义为 A[i] = A[i-1] + nums[i]; 定义A[-1] = 0;
        // 从A中取出两个不同的元素相减可以得到一个片段的和,A[j] - A[i] = nums[i+1] + nums[i+2] + ... + nums[j];
        // nums中的任意一个片段和对应与A中的两个元素或者是A中的一个单独的元素
        // 则A = {1, 3, 9, 12, 19, 24};
        // 考虑A中的元素对k取余数
        // A1 = {1, 0, 0, 0, 1, 0};
        // 当且仅当A1中的两个余数相同时,这两个前缀数组元素相减定义的片段和可以被k整除
        // 理解了以上概念,程序要做的只有两件事
        // 记录前缀数组中拥有相同余数的个数
        // 每次读入一个数,记录sum的余数,将记录中该余数的个数加入到计数器中
        // 此外要注意到的是,nums中的片段有两种定义
    public:
        void solution()
        {
            int size = 0, k = 0;
            cin >> size >> k;
            // vector<int> dp(size, 0);
            vector<int> sameRemainder(k + 1, 0);
            int count = 0;
            int sum = 0;
            int t = 0;
            for (int i = 0; i < size; i++)
            {
                cin >> t;
                sum = (sum + t) % k;
                if(sum == 0) 
                    count = (count + 1) % 1234567;
                // 存在前缀数组和的余数相同,则两个数组的差的和能被k整除
                count = (count + sameRemainder[sum]) % 1234567;
                sameRemainder[sum]++;
            }
            cout << count << endl;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        Solution so;
        so.solution();
    }
    
  • 1

信息

ID
1167
难度
8
分类
其他 | 数学 点击显示
标签
(无)
递交数
274
已通过
36
通过率
13%
上传者