目录
题目:
题目描述:
给你一个长度为 n 的数组,和一个基准数 m
问你最小分组数是多少,仍能保持各组内任意相邻两个数的和可以被基准数 m 整除?
( 特别的,如果组内只有一个数,则算做能被 m 整除 )
思路:
什么情况下,相邻两个数的和可以被 m 整除?( 设相邻两数为 a ,b )
当且仅当, ( a%m + b%m )% m == 0 的时候,相邻两数的和才能被 m 整除。
如,当 m == 8 的时候,我们只能让除 8 余 1 的和除 8 余 7 的相邻,除 8 余 2 的和除 8 余 6 的相邻,以此类推....
所以我们可以先按照余 m 的结果对原数组的数进行一个分类
对于余数 “互补” 的两个组,我们怎么统计最少分组?
如果两组数量相同,那交替排列( abab...ab ),如果有一组多一个,那也好办,可以(abab...aba)但如果多出一个以上,那么多出一个以上的部分都必须自己单独一组。(因为能跟他相邻的数已经用光了)
特别的,余 m 的恰好为 m ÷ 2 的组,可以直接自己为一组
这也就是为什么题目中第二个样例要分成 6 组
( 8 )( 1 7 1 )( 1 )( 2 6 )( 5 )( 4 4 )
思路有了,具体操作请看AC代码:
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int a[N];
int b[N];
void solve()
{
memset(b, 0, sizeof(b));//b数组进行初始化,防止上一个样例的数据影响
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)//通过余数进行分组
b[a[i] % m]++;
int cnt = 0;
if (b[0])//余0的直接为一组
cnt++;
for (int i = 1; i <= m / 2; i++)
{
int maxx = max(b[i], b[m - i]);
int minn = min(b[i], b[m - i]);
if (minn == 0)
{
cnt += maxx;
}
else //余 m 的恰好为 m ÷ 2 的组也被考虑在内了
{
int temp = maxx - minn;
cnt++;
cnt += (temp > 0 ? temp - 1 : 0);
}
}
cout << cnt << '\n';
}
int main()
{
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t; cin >> t;
while (t--)
solve();
return 0;
}