B. M-arrays
题目
题目大意
在一个给定的序列中让你重新划分子系列使得每个子序列里面相邻的元素相加之和能整除m,并且尽可能是的区间分的少。问最少能分多少个区间
解题思路
不管输入给数的有多大,加法取模可以先将加数取模(0不需要考虑),这样可以将原本不相同的数存放在同一个映射中,那么在询问是否有数之和能取模m,就是通过映射询问m-i的个数是否为0,如果不为0,最优的方法就是i与m-i间隔开来放,如果二者个数之差大于2,那么就需要将多余的元素逐个放在单独的区间,如果为0,就需要将i上的映射个数作为区间个数。
输入样例
4
6 4
2 2 8 6 9 4
10 8
1 1 1 5 2 4 4 8 6 7
1 1
666
2 2
2 4
输出样例
3
6
1
1
通过代码
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
using namespace std;
#define ll long long
#define sl(n) scanf("%lld",&n)
#define pl(n) printf("%lld",n)
#define sdf(n) scanf("%lf",&n)
#define pdf(n) printf("%.lf",n)
#define pE printf("\n")
#define ull unsigned long long
#define pb push_back
#define pre(n) for(ll i=1;i<=n;i++)
#define rep(n) for(ll i=n;i>=1;i--)
#define pi pair<ll,ll>
#define fi first
#define se second
ll a[100010];
int main()
{
ll t,n,m,i,j,cnt;
sl(t);
while(t--){
cnt=0;
sl(n),sl(m);
map<ll ,ll>b;
pre(n) {
sl(a[i]);
a[i]%=m;
b[a[i]]++;
}
ll temp[m];
memset(temp,0,sizeof(temp));
for(i=0;i<m;i++){
if(i==0&&b[i]){
cnt++,b[i]=0,temp[i]=1;continue;}
if(b[i]&&b[m-i]&&!temp[i]&&!temp[m-i]){
if(abs(b[i]-b[m-i])>=2){
cnt+=(abs(b[i]-b[m-i]));
}
else cnt++;
temp[i]=temp[m-i]=1;
b[m-i]=b[i]=0;
}
else if(b[i]&&!temp[i]){
cnt+=b[i];
temp[i]=1;
b[i]=0;
}
}
pl(cnt);
pE;
}
return 0;
}