专栏文章

题解:P14029 【MX-X20-T3】「FAOI-R7」重排序列(update)

P14029题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minwt4wp
此快照首次捕获于
2025/12/02 09:38
3 个月前
此快照最后确认于
2025/12/02 09:38
3 个月前
查看原文
我们需要最大化求和式:
i=1n((ai+bi)modm)\sum_{i=1}^{n} \left( (a_i + b_i) \bmod m \right)
则利用模运算性质:
(ai+bi)modm=ai+bim×ai+bim(a_i + b_i) \bmod m = a_i + b_i - m \times \left\lfloor \frac{a_i + b_i}{m} \right\rfloor
因此总和可表示为:
ai+bim×ai+bim\sum a_i + \sum b_i - m \times \sum \left\lfloor \frac{a_i + b_i}{m} \right\rfloor
  1. 设余数 ri=aimodmr_i = a_i \bmod msj=bjmodms_j = b_j \bmod m
  2. 其中:
ai+bjm=aim+bjm+I[ri+sjm]\left\lfloor \frac{a_i + b_j}{m} \right\rfloor = \left\lfloor \frac{a_i}{m} \right\rfloor + \left\lfloor \frac{b_j}{m} \right\rfloor + \mathbb{I}[r_i + s_j \geq m]
  1. 要最大化总和,我们需要最小化满足 ri+sjmr_i + s_j \geq m 的配对数。

不妨可以得出一下策略:
  1. rir_i 按升序排序。
  2. sjs_j 按降序排序。
  3. 使用双指针匹配:对每个 sjs_j,匹配满足 rim1sjr_i \leq m-1-s_j 的最小 rir_i
  4. 剩余元素自动满足 ri+sjmr_i + s_j \geq m

代码如下:
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
struct node{
	int a,b;
}r[N],s[N];
int a[N],b[N],c[N],u[N],v[N];
bool cmp1(node a,node b){return a.a<b.a;}
bool cmp2(node a,node b){return a.a>b.a;}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T;
	cin>>T;
	while(T--){
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++)cin>>a[i];
		for(int i=1;i<=n;i++)cin>>b[i];
		for(int i=1;i<=n;i++){
			r[i]={a[i]%m,i};
			s[i]={b[i]%m,i};
		}
		sort(r+1,r+n+1,cmp1);
		sort(s+1,s+n+1,cmp2);
		int k=0,t=0,w=0;
		for(int i=1;i<=n;i++){
			if(t<n&&r[t+1].a<=m-1-s[i].a)c[r[++t].b]=b[s[i].b];
			else u[++k]=s[i].b;
		}
		for(int i=t+1;i<=n;i++)v[++w]=r[i].b;
		for(int i=1;i<=w;i++)c[v[i]]=b[u[i]];
		int c1=0,c2=0;
		for(int i=1;i<=n;i++){
			c1+=a[i]%m;
			c2+=b[i]%m;
		}
		int ans=c1+c2-m*(n-t);
		cout<<ans<<'\n';
		for(int i=1;i<=n;i++)cout<<c[i]<<' ';
		cout<<'\n';
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...