Aamazon笔试题(Number of Groups )
题意:
Given an array Arr[] of N distinct integers. Write a program to find the count of groups of 2 or 3 integers that can be formed by choosing integers from the given array such that sum of integers in each of the group is divisible by three.
给你一个带有N个不同整数的数组,问能够选择出来多少组只有2个或者3个的组的和被3整除。
输入描述:
第一行表示测试的组数,第二行是n的大小,接下来是输入数组。
输出描述:
每一测试输出一个数,表示组数。
Constraints:
1<=T<=100
1<=N<=105
1<=Arr[i]<=105
Example:
Input:
2
6
1 5 7 2 9 14
4
3 6 9 12
Output:
13
10
分析:
暴力解决问题?当然可以。只需要一个两层训练+一个三层循环就直接出来结果。但是出来在笔试或者面试时,只给出这种答案,面试官可是不怎么高兴的,而且对于本题的数组范围,应该也会超时。解决这个题,我们有一个有关余数的定理,对于一个k,如果n%k = a,m%k = b,则有(n+m) % k = (n%k + m%k) % k = (a+b) % k,如果(a+b)%k = 0,则有(n+m)%k = 0。有了上面这个定理,我们只需要纪录数组中余数0,1,2的个数,从0,1,2中进行2个数或者3个数的组合计数,就可以得到结果,能够被3整除的情况共有如下几种:
1、 0+0 (选择两个能够被三整除的数)
2、 0+0+0 (选择3个能够被三整除的数)
3、 1+2 (选择1个余数是1的数和一个余数是2的数)
4、0+1+2 (选择1个余数是1的数和一个余数是2的数和一个余数是0的数)
5、 1+1+1 (选择3个余数是1的数)
6、 2+2+2 (选择3个余数是2的数)
假如数组c[3]表示余数的个数,c[0]表示余数是0的个数,c[1]表示余数是1的个数,c[2]表示余数是2的个数,上述对应的情况的个数如下:
1、 c[0]*(c[0]-1)/2
2、 c[0](c[0]-1)(c[0]-2) / 6;
3、 c[1]*c[2];
4、 c[0]*c[1]*c[2];
5、 c[1](c[1]-1)(c[1]-2) / 6;
6、 c[2](c[2]-1)(c[2]-2) / 6;
相加就得到结果。
Code:
/**
*Author: xiaoran
*座右铭:既来之,则安之
*/
/**
*
*从一个数组中,选出2或者3个数,使得他们的和能够被3整除,
* 为有多少中选择的方式。
* 余数定理,如果a % 3 = 1,b % 3 = 2则 (a+b)%3=0
* 我们只需要纪录每个数模3之后的余数的个数,从余数中进行2、3组合即可
* 共有以下集中情况:直接用0,1,2表示余数为0,1,2的数字
* 1、 0+0 (选2个能够被3整除的数)
* 2、 0+0+0 (选3个能够被3整除的数)
* 3、 1+2
* 4、 0+1+2
* 5、 1+1+1
* 6、 2+2+2
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<string.h>
using namespace std;
typedef long long LL;
const int MAXN = 1005;
int main() {
//code
int t,n,x;
cin>>t;
while(t--){
cin>>n;
int c[3] = {0};
for(int i=0;i<n;i++){
cin>>x;
c[x%3]++;
}
int sum = 0;
// 按照上述的情况进行加法原则
sum += c[0]*(c[0]-1) / 2;
sum += c[0]*(c[0]-1)*(c[0]-2) / 6;
sum += c[1]*c[2];
sum += c[0]*c[1]*c[2];
sum += c[1]*(c[1]-1)*(c[1]-2) / 6;
sum += c[2]*(c[2]-1)*(c[2]-2) / 6;
cout<<sum<<endl;
}
return 0;
}