CF1227B题解
CF1227B题解
题意
给一个数组 \(q\),其中:
- \(q_1=p_1\)。
- \(q_2=\max(p_1,p_2)\)。
- \(q_3=\max(p_1,p_2,p_3)\)。
- \(\cdots\)
- \(q_n=\max(p_1,p_2,p_3,\cdots p_n)\)
求符合要求的 \(p\) 数组。
思路
有以下两点:
- 无解的情况:\(q[i]<i\),为啥呢?答:那是因为 \(q\) 数组的第 \(i\) 个是为 \(p\) 的前 \(i\) 个数中最大的。又因为 \(p\) 为 \(1\sim n\) 中不重复的数字组成的数组。所以要是 \(q[i]<i\),就是无解。
- 求解操作呢,我借鉴了 SunArrebol 这位大佬,但是他没有解释,首先先讲解法:
bool ok=0;//记录是否有符合题意的p数组
for(int i=1; i<=n; i++) p[i]=i;
for(int i=1; i<=n; i++){
scanf("%d",&q[i]);
if(q[i]<i) ok=1;//标记为无解。
else swap(p[i],p[q[i]]);//交换
}
那为啥是上面那样呢?首先一开始已经赋值 \(p\) 为 \(1,2,3,\cdots n\),此时录入 \(q\),无解就不说了,我们要理解的是交换这一步,为啥是这样交换呢?分析如下:
我们都知道,\(q\) 数组的第 \(i\) 个是为 \(p\) 的前 \(i\) 个数中最大的,那么输入一个 \(q[i]\) 分为以下两种情况:
\(\begin{cases} q[i]=p[i]=\max(p[1],p[2],p[3],\cdots p[i])\\p[i]\neq\max(p[1],p[2],p[3],\cdots p[i]),q[i]=q[i-1] \end{cases}\)
对于第一种情况,\(p[i]\) 是没有被交换过的,所以 \(q[i]=p[i]=i\),所以交换了等于没交换。
对于第二种情况,因为 \(q[i]=q[i-1]\),所以就说明前面 \(p[q[i]]\) 已经交换过原来的小的了,在 \(p[q[i]]<p[i]<q[i]\),所以也不影响 \(q\) 数组最大值,操作合理。
总结
- 在做操作的时候记得赋初值。
- 记得特判无解的情况。
- 别忘了换行!
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int p[100005],q[100005],T,n;
int main(){
scanf("%d",&T);
while(T--){//有T组数据
scanf("%d",&n);
bool ok=0;//记录是否有符合题意的p数组
for(int i=1; i<=n; i++) p[i]=i;//赋初值
for(int i=1; i<=n; i++){
scanf("%d",&q[i]);
if(q[i]<i) ok=1;//标记为无解。
//为啥无解呢?
//那是因为:q数组的第i个是为p的前i个数中最大的。
//又因为p为1~n中不重复的数字组成的数组。
//所以要是q[i]<i,就是无解。
else swap(p[i],p[q[i]]);//交换
}
if(ok==1) printf("-1");//无解
else for(int i=1; i<=n; i++) printf("%d ",p[i]);
printf("\n");//记得换行
}
return 0;
}