QQzhi
2024-11-19 20:41:43
题面中文翻译(已提交后台)
这道题仅要求正解,要求较低,只需写出一套正确的处理流程即可。
性质分析 · 一
拿到数列的操作方式,我们先来分析一下性质。可知其可拆分为两个行为,后面处理时分别会用到。
void op(int i){
hst[top++]=i; // 操作记录数组
swap(a[i],a[i+1]);
a[i]+=k;
}
先设数列
对数列
依次进行操作
我们发现,经过
故可以定义一个数列操作
故我们可以通过抬升逆序对其中一方的区间,逐步消除逆序对。
void add(int i){
int len=n-i+1;
for (int j=0;j<len;j++)
for (int k=i;k<n;k++)
hst[top++]=k;
for (int j=i;j<=n;j++)
a[j]+=(len-1)*k;
}
性质分析 · 二
当
可知若
针对性特判掉长度为
原数列为一个二元组时进行特判,若为逆序对,当
消除最后两个元素可能构成的逆序对
二元组内处理逆序情况限制颇多。既然经过特判,此处可放心引入
操作完成后我们不关心
void judge(){ // 使 (A[n-1],A[n]) 单调不减&决断
if (n==2){ // 特判
if (a[1]<a[2]+k&&a[1]>a[2])
cout<<"No",exit(0);
else{
if (a[1]>a[2])
op(1);
return;
}
}
while (a[n-2]>a[n])
add(n-1);
op(n-2);
}
尽情消除队列中所有逆序对!
扫描检查,发现数列中相邻两数为逆序对
void order(){ // 逐一使 A[i...n-1] 单调不减
for (int i=1;i<n-1;i++)
while (a[i]>a[i+1])
add(i+1);
}
以下供参。
#include <iostream>
#include <algorithm>
using std::cin;using std::cout;using std::swap;
constexpr int N=1e5+1;
int n,k,a[N],hst[500000],top;
void init(){
cin>>n>>k;
for (int i=1;i<=n;i++)
cin>>a[i];
}
void op(int i){
hst[top++]=i;
swap(a[i],a[i+1]);
a[i]+=k;
}
void add(int i){
int len=n-i+1;
for (int j=0;j<len;j++)
for (int k=i;k<n;k++)
hst[top++]=k;
for (int j=i;j<=n;j++)
a[j]+=(len-1)*k;
}
void judge(){ // 使 (A[n-1],A[n]) 单调不减&决断
if (n==2){ // 特判
if (a[1]<a[2]+k&&a[1]>a[2])
cout<<"No",exit(0);
else{
if (a[1]>a[2])
op(1);
return;
}
}
while (a[n-2]>a[n])
add(n-1);
op(n-2);
}
void order(){ // 逐一使 A[i...n-1] 单调不减
for (int i=1;i<n-1;i++)
while (a[i]>a[i+1])
add(i+1);
}
void solve(){
judge();
order();
cout<<"Yes\n"<<top<<'\n';
for (int i=0;i<top;i++)
cout<<hst[i]<<' ';
}
int main(){
cin.tie(0)->sync_with_stdio(0);
init();
solve();
}