枚举算法实践6-数组配对 C++

题目描述

给你一个长度为n的数组和一个正整数k,问从数组中任选两个数使其和是k的倍数,有多少种选法
对于数组a1=1 , a2=2 , a3=2而言:
(a1,a2)和(a2,a1)被认为是同一种选法;
(a1,a2)和(a1,a3)被认为是不同的选法。

输入数据

第一行有两个正整数n,k。n<=1000000,k<=1000000 第二行有n个正整数,每个数的大小不超过1e9

输出数据

选出一对数使其和是k的倍数的选法个数

样例输入

5 6
1 2 3 4 5

样例输出

2

样例说明

a1+a5=6,a2+a4=6,都是6的倍数
所以符合条件的选法有(1,5),(2,4)

解题思路1

  • 时间复杂度较高的解法
  • 对数组进行两层循环遍历,0<i<n和i<j<n
  • 一一列举每一对(ai,aj)并判断
  • 判断:(ai+aj) % k == 0,若成立,解法+1
  • 时间复杂度O(n2)

代码1

//两层的循环 时间复杂度较高
#include <iostream>
#include <cstring>
using namespace std;
int n, k;
int a[1000001];
int main()
{
    memset(a, 0, sizeof(a)); //初始化
    cin >> n >> k;
    long long ans = 0;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            if ((a[i] + a[j]) % k == 0)
                ans++;
        }
    }
    cout << ans;
    return 0;
}

解题思路2

  • 下面进行优化枚举对象

  • 不难理解: (ai+aj)%k=0 可以转化为 (ai%k + aj%k) %k = 0 如: (31+5)%6 =0 -> (31%6+5%6)%6=0

  • 由此,我们可以把余数相同的数组元素合并为一个子集cnt,然后把子集cnt作为枚举对象

  • 那么对于组合问题,就是两个之和为k的cnt相乘

  • 这里要特别注意i=0和i=k/2的情况,因为相加的对称性,这两种情况下,在循环中,是重复算了两遍的。

代码2

#include <iostream>
#include <cstring>
using namespace std;
long long cnt[1000001];
int main()
{
    long long n, k;
    cin >> n >> k;
    while (n--)
    {
        int temp;
        cin >> temp;
        cnt[temp % k]++; //当前数字对k取余
    }
    long long ans;
    //注意对i=0以及i=k/2要特判
    ans = cnt[0] * (cnt[0] - 1) / 2;
    for (int i = 1; i < (k + 1) / 2; i++)//从1~(k + 1) / 2遍历
        ans += cnt[i] * cnt[k - i];
    if (k % 2 == 0)
        ans += cnt[k / 2] * (cnt[k / 2] - 1) / 2;
    cout << ans;
    return 0;
}

小结

  • 对于枚举算法的优化,可以从以下两点进行考虑:优化模型—针对问题特征,优化对象模型;优化过程—针对对象特征,优化列举和验证过程
  • 若文章存在问题,还请各位大佬批评指正,共同进步。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值