Codeforces Round #636 (Div. 3) 比赛人数12253
[codeforces 1343F] Restore the Permutation by Sorted Segments 从假定出发的尝试
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址http://codeforces.com/contest/1343/problem/F
| Problem | Lang | Verdict | Time | Memory |
|---|---|---|---|---|
| F - Restore the Permutation by Sorted Segments | GNU C++17 | Accepted | 46 ms | 200 KB |
思路摘自https://www.cnblogs.com/heyuhhh/p/12753964.html
考虑从前往后构造出原排列。
假设我们知道了第一个位置的元素,那么据此可以求出第二个位置的元素,以此类推就可以求出所有的元素。
已知第i-1个元素,求第i个元素的方法:我们考虑所有的序列,如果一个序列中删光已被确定位置的数后,未出现的数的个数为1,我们此时就可以选定该未出现的数其作为第i个数。
这样做的正确性是显然的,如果我们不选这个元素而选其它的元素,那么显然这个元素和序列中其它元素不在一个序列中。
那么我们直接枚举第一个元素,然后依次找后面的元素即可。如果找到合法的就直接输出。
PS.其实这个题最容易的想法是从后往前找,因为每次最后一个位置的数只会出现一次,但最前面的数也可能出现一次。这样的话就需要多考虑一些情况来判断当前是否合法,码量会很大。但是如果注意到了这样一个性质就比较容易想到从第一个开始找,就是每次我们开头都是一个长度为2的区间,删去第一个后很容易找到下一个,下一个也是一个长度为2的区间的开头...然后以此类推。从后往前的话就不具备这样的性质。
若不明白上述说法,请看样例模拟如下
5
2 2 5
3 2 3 5
4 2 3 4 5
5 1 2 3 4 5
2 5 3 4 1
1.假定位置1值是1
位置 1 2 3 4 5
数值 1 0 0 0 0
寻找位置2的数值
数据段2 5,没有已固定位置的数据可删除,故在此次判定中无用
数据段2 3 5,没有已固定位置的数据可删除,故在此次判定中无用
数据段2 3 4 5,没有已固定位置的数据可删除,故在此次判定中无用
数据段1 2 3 4 5,删除已固定位置的数值1,成为了数据段2 3 4 5,
但还是无法判定剩下的数据位置,故在此次判定中无用
经尝试,位置1值是1,假定错误。
2.假定位置1值是2
位置 1 2 3 4 5
数值 2 0 0 0 0
寻找位置2的数值
数据段2 5,删除已固定位置的数值2,成为了数据段5,故可让位置2值是5
位置 1 2 3 4 5
数值 2 5 0 0 0
寻找位置3的数值
数据段2 3 5,删除已固定位置的数值2,5,成为了数据段3,故可让位置3值是3
位置 1 2 3 4 5
数值 2 5 3 0 0
寻找位置4的数值
数据段2 3 4 5,删除已固定位置的数值2,5,3,成为了数据段4,故可让位置4值是4
位置 1 2 3 4 5
数值 2 5 3 4 0
寻找位置5的数值
数据段1 2 3 4 5,删除已固定位置的数值2,5,3,4,成为了数据段1,故可让位置5值是1
位置 1 2 3 4 5
数值 2 5 3 4 1
经尝试,位置1值是2,假定正确。
AC代码如下
最难懂的代码
else if(pos[b]>=i-a[j][0]+1)r--;//我们认为a[j][]右边界对应位置i,a[j][]左边界起始位置对应i-a[j][0]+1,pos[b]必须落在[i-a[j][0]+1,i]范围之内,才能被删除,故pos[it]>=i-a[j][0]+1
#include <stdio.h>
#define maxn 205
int n,a[maxn][maxn],pos[maxn],ans[maxn];
int judge(){
int i,j,k,r,x,b;
for(i=2;i<=n;i++){//i代表位置,从位置2开始寻找
for(j=1;j<n;j++){//尝试给定的数据段,请注意,我们让尝试的数据段右边界与i重合
r=a[j][0],x=-1;
for(k=1;k<=a[j][0];k++){
b=a[j][k];
if(!pos[b])x=b;
else if(pos[b]>=i-a[j][0]+1)r--;//我们认为a[j][]右边界对应位置i,a[j][]左边界起始位置对应i-a[j][0]+1,pos[b]必须落在[i-a[j][0]+1,i]范围之内,才能被删除,故pos[it]>=i-a[j][0]+1
}
if(r==1&&x!=-1){ans[i]=x,pos[x]=i;break;}//找到i位置的数据
}
if(ans[i]==0)return 0;//若找不到
}
return 1;
}
int main(){
int t,i,k,j;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d",&k),a[i][0]=k;//a[i][0]=k存储该段数据长度
for(j=1;j<=k;j++) scanf("%d",&a[i][j]);
}
for(i=1;i<=n;i++){//尝试第一个位置的值是i
for(j=1;j<=n;j++)ans[j]=0,pos[j]=0;//初始化
ans[1]=i;//第一个值是i
pos[i]=1;//i值所处的位置是1
if(judge())break;
}
for(i=1;i<n;i++)printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}
本文详细解析了Codeforces Round#636 (Div.3)中的F题“Restore the Permutation by Sorted Segments”。通过从前向后尝试构建原排列的方法,阐述了解题思路和步骤,并提供了AC代码示例。
372

被折叠的 条评论
为什么被折叠?



