题意:
已知一个序列a,问能否将a映射到序列b,使得相邻元素之间的大小关系不变(三种),且相邻元素不能相差超过k,且每个元素范围在[L,R]内。如果能,求字典序最小的b。
思路:
可以设b[1]的范围为[L,R],从前往后遍历求出b[2]~b[n]每个元素的上界和下界。如果其中有元素已经没有可以使之前成立的范围了,那么说明无法构造这样的映射。
此时最后一个元素的上下界是正确的,从后往前遍历即可得到正确序列B,但是若要保证字典序最小,则每个元素应该取最小的可行取值(如果开始先从后往前扫求出范围,再从前往后贪心地选最小取值更容易理解,但是反过来也是正确的贪心策略)。
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int l[maxn],r[maxn],a[maxn];
int ans[maxn];
int main(){
int n,L,R,k;
cin>>n>>L>>R>>k;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
l[1]=L;r[1]=R;
for(int i=2;i<=n;i++){
if(a[i]==a[i-1]){
l[i]=l[i-1];
r[i]=r[i-1];
}
else if(a[i]>a[i-1]){
l[i]=l[i-1]+1;
r[i]=min(r[i-1]+k,R);
}
else if(a[i]<a[i-1]){
l[i]=max(L,l[i-1]-k);
r[i]=r[i-1]-1;
}
if(l[i]>r[i]||r[i]<L||l[i]>R){
printf("-1
");
return 0;
}
}
ans[n]=l[n];
for(int i=n-1;i>=1;i--){
if(a[i]==a[i+1])
ans[i]=ans[i+1];
else if(a[i]<a[i+1]){
//ans[i+1]-k<=ans[i]<=ans[i+1]-1
//l[i]<=ans[i]<=r[i]
ans[i]=max(ans[i+1]-k,l[i]);
}
else if(a[i]>a[i+1]){
//ans[i+1]+1<=ans[i]<=ans[i+1]+k
//l[i]<=ans[i]<=r[i]
ans[i]=max(ans[i+1]+1,l[i]);
}
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
printf("
");
}