[ABC416D] Match, Mod, Minimize 2

题面-[ABC416D] Match, Mod, Minimize 2

算法关键词:贪心,思维题

题目大意:给出两个长度为 \(n\) 的数组 \(A\)\(B\) 和一个取模数 \(M\),可以随意重新排列数组 \(A\),计算 \(\sum_{i=1}^{n}((A_i+B_i) \bmod M)\) 的值,问最小的值是多少。

首先注意到和要对 \(M\) 取模,又看到数据范围中有

\(0\le A_i,B_i \le M\)

也就是说两数相加后最多减去一个 \(M\) 。而我们希望结果最小,就要减去尽可能多的 \(M\),很容易想到用贪心的方法解决。
当然首先要给两数组排个序。欸题目中不是说只排序 \(A\) 数组吗
因为这道题允许我们排序 \(A\) 数组,而且求和\(A\),\(B\) 数组内部的位置没关系,只\(A_i\),\(B_j\) 的相对位置有关系,所以实际上两个数组都可以更改顺序
所以直接排序完后从大到小枚举\(x\),匹配最小的满足\(y\ge M-x\)\(y\)(保证取模后的数最小),如果不存在则匹配最小的未匹配的数即可。
代码实现不长 (开心) ,时间复杂度\(O(Tn)\)

#include <bits/stdc++.h>
using namespace std;

const int N=300010;

int a[N],b[N];

bool cmp(int x,int y){
	return x>y;
}

int main (){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		int ans=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			ans+=a[i];
		}
		for(int i=1;i<=n;i++){
			scanf("%d",&b[i]);
			ans+=b[i];
		}
		sort(a+1,a+n+1);
		sort(b+1,b+n+1,cmp);
		int sum=0,j=1;
		for(int i=1;i<=n;i++){
			while(j<=m&&b[j]+a[i]>=m) j++;
			if(sum!=j-1) sum++;
		}
		printf("%d\n",ans-sum*m);
	}
	return 0;
}

posted @ 2025-08-27 10:21  lnquoein  阅读(25)  评论(0)    收藏  举报