题解: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;
}

浙公网安备 33010602011771号