题解:CF2103E Keep the Sum

题意

给你一个整数 \(K\) 和长度为 \(n\) 的序列 \(a\)\(a_i \in [0,K]\)。你可以进行如下操作不超过 \(3n\) 次:

  • 首先,选择两个下标 \(i \not = j\),要求 \(a_i+a_j=K\)
  • 再选择一个 \(x\),将 \(a_i\) 减少 \(x\),将 \(a_j\) 增加 \(x\)
  • 要求每次操作完上一步后仍满足 \(a_i,a_j \in [0,K]\)

是否能将 \(a\) 序列变为不降的?输出方案或判断无解。\(n \leq 2 \times 10^5,K \leq 10^9\)

题解

下文称两个数匹配等价于两数之和为 \(K\)

由排序想到,是否能间接地达成 \(Swap(a_i,a_j)\) 的操作。

\(a_i+a_j=K\) 时可以(废话)。当存在 \(k\) 使得 \(a_i,a_k\) 匹配也是可以的:

先操作 \((a_i,a_k)\)\(a_i\) 变成和 \(a_j\) 相等,再操作 \(a_j,a_k\)\(a_j\) 变成最初的 \(a_i\),完成了交换。

可惜其他情况我们没法实现交换。所以我们要想办法使那些不能匹配的变成能匹配的。

先任意找一对匹配的数 \(a_x,a_y\),把 \(a_x\)\(a_1\) 交换,\(a_y\)\(a_n\) 交换,(此时 \(a_1,a_n\) 就匹配了)再操作 \((a_1,a_n)\) 使得 \(a_1=0,a_n=K\)

这时候我们发现,\(i \in [2,n-1]\) 的所有 \(a_i=0\)\(a_i=K\) 都有匹配了(即 \(a_1\)\(a_n\)),只需要把所有 \(a_i=0\) 加入到 \(a_1\) 的后面,所有 \(a_n\) 加入到 \(a_n\) 的前面。再把加入的最后一个 \(0\) 和加入的最后一个 \(K\) 改成 \((1,K-1)\),我们就可以加入剩下所有的 \(a_i=1\)\(a_i=K-1\)……

于是,任意时刻,排好序的部分都是一段前缀和一段后缀,每次加入能加入的数即可。

细节

无解的判断:原序列不是有序的,且不存在一对匹配的 \(a_x,a_y\)

\(K\) 很大,所以注意离散化,离散化的时候要把 \(a_i\)\(K-a_i\) 都丢进去,这样离散化前后配对的值才能保持不变。

快速维护值和下标的映射关系可以用 set。在交换的时候同步维护位置。

实现一个 Swap 函数会让代码简洁很多。特判 Swap(i,i) 的情况,要直接 return。这种操作会被认为是不合法的。

代码

提交记录

#include<bits/stdc++.h>
#define pb push_back
#define For(i,il,ir) for(int i=(il);i<=(ir);++i)
using namespace std;
const int maxn=2e5+10;

int K,n;
int a[maxn];
int h[maxn<<1],px,py;
set<int> st[maxn<<1];
vector<int> ai,aj,ax;

#define Print(ii,jj,xx) ai.pb(ii),aj.pb(jj),ax.pb(xx)
#define Insert(p) st[a[p]].insert(p)
#define Erase(p) st[a[p]].erase(p)
void Swap(int x,int to,int y){
	if(x==to) return;
	Print(x,y,h[a[x]]-h[a[to]]);
	Print(to,y,h[a[to]]-h[a[x]]);
	Erase(x),Erase(to),swap(a[x],a[to]);
	Insert(x),Insert(to);
}
void solve()
{
	For(i,1,n) h[i-1]=a[i],h[i+n-1]=K-a[i];
	sort(h,h+n+n),K=unique(h,h+n+n)-h-1;

	px=py=-1;
	For(i,1,n){
		a[i]=lower_bound(h,h+K+1,a[i])-h;
		if(st[K-a[i]].size())
			px=*st[K-a[i]].begin(),py=i;
		Insert(i);
	}
	if(px==-1){ puts("-1");return; }

	Swap(px,1,py); px=1;
	Swap(py,n,px); py=n;
	Erase(1),Erase(n);

	for(int v=0;v<K-v;v++){
		Print(px,py,h[a[px]]-h[v]);
		a[px]=v,a[py]=K-v;
		while(!st[v].empty())
			Swap(*st[v].begin(),++px,py),Erase(px);
		while(!st[K-v].empty())
			Swap(*st[K-v].begin(),--py,px),Erase(py);
	}
	printf("%d\n",(int)ai.size());
	for(int i=0;i<ai.size();i++)
		printf("%d %d %d\n",ai[i],aj[i],ax[i]);
}
void clear(){
	For(i,0,K) st[i].clear();
	ai.clear(),aj.clear(),ax.clear();
}
signed main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&K);
		bool flag=true;
		For(i,1,n) 
			scanf("%d",&a[i]),flag&=(a[i]>=a[i-1]);
		if(flag) puts("0");
		else solve(),clear();
	}
	return 0;
}
posted @ 2025-04-25 14:22  wanggk  阅读(27)  评论(0)    收藏  举报