题目描述
难度分:1700
输入n(1≤n≤105)、l、r(1≤l≤r≤109)和长为n的数组a(l≤a[i]≤r),以及一个1~n的排列p。
有两个长为n的数组a和b,元素范围均在[l,r]中。数组a已经输入给你了,但你不知道b。
定义c[i]=b[i]−a[i]。已知数组c中的元素互不相同,且c离散化后的结果是排列p。
构造一个符合要求的数组b。如果无法构造,输出−1。
输入样例1
5 1 5
1 1 1 1 1
3 1 5 4 2
输出样例1
3 1 5 4 2
输入样例2
4 2 9
3 4 8 9
3 2 1 4
输出样例2
2 2 2 9
输入样例3
6 1 5
1 1 1 1 1 1
2 3 5 4 1 6
输出样例3
-1
算法
构造
先初始化一个二元组数组tup,存储信息(p[i],i),然后将其排序。我们最关键的其实是确定c数组,这样就能通过b[i]=a[i]+c[i]的关系把b数组构造出来。
由于构造出来的b[i]需要属于区间[l,r],先让p[i]=1的那个位置满足条件,留最大的余地,让b[i]=l,此时c[i]=l−a[i],其中i=tup[0][1]。然后遍历i∈[1,n),令pre=c[i]开始构造其他元素。
初始化c[i]=pre+1,分为以下三种情况:
- 如果b[i]=a[i]+c[i]<l,说明c[i]太小了,让它增加l−c[i]−a[i],这样就能把b[i]平移到l位置。
- 如果b[i]=a[i]+c[i]>r,由于一直都保留最大的余地,使用小的p值使构造出来的b值尽量比l大不了多少,所以肯定无解了。
- 否则b[i]是合法的,不用管。
之后令pre=c[index]继续构造剩下的元素。
复杂度分析
时间复杂度
对二元组数组tup排序之后,后面的构造过程是线性的,因此整个算法的时间复杂度为O(nlog2n)。
空间复杂度
除了输入的a、p两个数组,额外空间有二元组数组tup、c数组和最后的答案数组b,都是线性空间。因此,整个算法的额外空间复杂度为O(n)。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, l, r, a[N], p[N], b[N], c[N];
int main() {
scanf("%d%d%d", &n, &l, &r);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &p[i]);
}
vector<array<int, 2>> tup;
for(int i = 1; i <= n; i++) {
tup.push_back({p[i], i});
}
sort(tup.begin(), tup.end());
c[tup[0][1]] = l - a[tup[0][1]];
int pre = c[tup[0][1]];
bool ok = true;
b[tup[0][1]] = a[tup[0][1]] + c[tup[0][1]];
for(int i = 1; i < n; i++) {
int index = tup[i][1];
c[index] = pre + 1;
if(a[index] + c[index] < l) {
c[index] += l - c[index] - a[index];
}else if(a[index] + c[index] > r) {
ok = false;
}
b[index] = a[index] + c[index];
pre = c[index];
}
if(ok) {
for(int i = 1; i <= n; i++) {
printf("%d ", b[i]);
}
puts("");
}else {
puts("-1");
}
return 0;
}