JZOJ100031.【NOIP提高A组模拟】外星密码

Description在这里插入图片描述

SOLUTION

  • 结论题、大水题,然鹅我考场上并没有想到结论(甚至可以说根本就没有往那个十分显然的规律上想),无限觉得这题不可做却又觉得很水。。。。。。
  • 首先显然最后一列为答案的集合
  • 显然将其排序得到第一列前面一堆0,后面一堆1,于是最后一列与第一列的每一位置一一相连。现在有一个问题就是我们不知道哪个0对应的是哪个0。
  • 这里有一个性质:假设最后一个位置i对应的是第一列的r[i],如果a[x]=a[y],x<y,r[x]<r[y]。也就是最前的0对应左列最前的0.
  • 证明: 两个位置i,j,a[i]=a[j],i<j,即以i为结尾的字典序要比以j为结尾的字典序小,由于最后一位相同不考虑,那么下一位的r[i]就应该在r[j]的前面,才能满足条件。
  • 所以以最右列的第一个0为起点跳一跳就好了
  • 其实输入有一种无解的情况,就是当有a[k]=1时a[1]=0,因为这样的话对应的第一列也为0,但实际上如果将这个0移到前面答案更优,所以不会“跳不动”。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 10005
using namespace std;

int n,i,j,t,b[maxn];
struct arr{int x,y;} a[maxn];
int cmp(arr a,arr b){return a.x<b.x||a.x==b.x&&a.y<b.y;}

int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].y=i,b[i]=a[i].x;
	sort(a+1,a+1+n,cmp);
	t=a[1].y;
	for(i=1;i<=n;i++) 
		printf("%d ",b[t]),t=a[t].y;
}
原文地址:https://www.cnblogs.com/DeepThinking/p/11700962.html