奶牛摄影

奶牛摄影

奶牛们今天非常调皮。

农夫约翰想给站成一排的奶牛拍一张照片,但是在他有机会拍下照片之前,奶牛一直在移动。

具体的说,约翰有 $N$ 头奶牛,编号 $1 \sim N$。

约翰想拍一张奶牛以特定顺序站成一排的照片,这个顺序可以用数组 $A\left[ {1..N} \right]$ 来表示,其中 $A\left[ j \right]$ 表示排列中第 $j$ 头奶牛的编号。

他按这个顺序将奶牛排成一排,但就在他按下相机上的按钮拍摄照片之前,最多一头奶牛移动到了新的位置上。

更准确地说,要么没有奶牛移动,要么一头奶牛离开她在队列中的当前位置,然后重新插入到队列中的新位置。

约翰非常沮丧,但并没有灰心,他再次按照数组 $A$ 的顺序,排列了他的奶牛。

但是,就在他再次拍照之前,又有最多一头奶牛移动到了队列中的新位置。

在约翰放弃之前,上面的过程一共重复了五次,拍下了五张照片。

给定每张照片的内容,请你推断出最初的预定顺序 $A$。

每张照片显示的都是在预定顺序下,最多一头奶牛移动后的奶牛排列顺序。

每头奶牛最多只会在拍摄一张照片时移动,如果一头奶牛在拍摄一张照片时移动了,那么她就不会在拍摄其他照片时主动移动。(尽管由于其他奶牛的移动,她最终可能会处于不同的位置)

输入格式

第一行包含整数 $N$,表示奶牛数量。

接下来 $5N$ 行,每 $N$ 行描述一张照片中的奶牛顺序,每行包含一个奶牛的编号。

输出格式

共 $N$ 行,输出预定顺序 $A$,每行输出一个奶牛编号。
可以证明,本题解唯一。

数据范围

$1 \leq N \leq 20000$

输入样例:

5
1 
2 
3 
4 
5
2
1
3
4
5
3
1
2
4
5
4
1
2
3
5
5
1
2
3
4

输入样例:

1
2
3
4
5

 

解题思路

   思维题,比较难想到。一共拍了$5$次照片,每次最多会有$1$头牛改变位置,并且当有一头牛主动改变位置后,那么这头牛在其他的照片中就不会再主动改变位置。现在要根据$5$张照片来推断原始的序列是什么。

  我们关注某两头牛的位置关系,假设在原序列中$A$在$B$的前面,我们来看看这$5$张照片中有多少张$A$在$B$的前面。如果一张照片中$A$和$B$都没有主动改变位置,那么$A$一定会在$B$的前面。当一张照片中$A$主动改变位置(只有$A$改变,因为一张照片最多只有一头牛主动改变位置),那么$A$移动的新的位置既可以在$B$的前面,也可以在$B$的后面,因此如果只改变$A$的位置,那么最多会有一张照片$A$在$B$的后面。同理如果只改变$B$的位置,那么最多会有一张照片$A$在$B$的后面。因此最多会有两张照片$A$会在$B$的后面,在剩余的照片中$A$都在$B$的前面。

  因此,如果原始序列中$A$在$B$的前面,那么在$5$张照片中,$A$在$B$前面的照片的次数一定$\geq 3$,$A$在$B$后面的照片的次数一定$\leq 2$,即$A$在$B$前面的次数要比$A$在$B$后面的次数多。

  对于任何两头牛$A$和$B$,如果原序列中$A$在$B$的前面,就等价于在$5$张照片中$A$在$B$前面的照片的次数比$A$在$B$后面的次数多(本题关键)。

  为什么保证有唯一解呢。我们分析发现,如果在原始序列中,$A$在$B$的前面那么一定有$A$在$B$前面的照片的次数$\geq 3$,$A$在$B$后面的照片的次数$\leq 2$,这就可以唯一确定任意两头牛的关系(因为$\geq 3$和$\leq 2$这两个范围没有交集,情况唯一确定)。又因为$A$在$B$后面的照片的次数必然$\leq 2$,假设有$x$张照片,那么$A$在$B$前面的照片的次数就是$\geq x - 2$,为了唯一确定$A$和$B$在原序列中的位置,必须要有$x - 2 > 2$,即$x > 4$。

  因此为了知道每张照片中任意两头牛的位置先后关系,我们用数组存每头牛位置,比如第$i$张照片中编号为$k$的牛在$j$这个位置,那么就有$p \left[ {i, k} \right]  = j$。

  接下来就是一个排序的过程了,如果发现在$5$张照片中$A$在$B$前面的次数$\geq 3$,那么$A$就排在$B$的前面,这就需要我们手写一个比较函数来判断$A$和$B$的位置。

  最后输出排序后的结果就可以。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e4 + 10;
 5 
 6 int p[5][N];
 7 int ans[N];
 8 
 9 bool cmp(int a, int b) {
10     int cnt = 0;
11     for (int i = 0; i < 5; i++) {   // 遍历5张照片,统计a出现在b前面的次数
12         if (p[i][a] < p[i][b]) cnt++;
13     }
14     
15     return cnt >= 3;
16 }
17 
18 int main() {
19     int n;
20     scanf("%d", &n);
21     for (int i = 0; i < 5; i++) {
22         for (int j = 1; j <= n; j++) {
23             int val;
24             scanf("%d", &val);
25             p[i][val] = j;  // 存每头牛的在序列中对应的位置
26         }
27     }
28     
29     for (int i = 1; i <= n; i++) {
30         ans[i] = i; // 一开始假设第i头牛在i这个位置
31     }
32     sort(ans + 1, ans + 1 + n, cmp);    // 根据牛的位置进行排序
33     for (int i = 1; i <= n; i++) {
34         printf("%d\n", ans[i]);
35     }
36     
37     return 0;
38 }

 

参考资料

  AcWing 2049. 奶牛摄影(春季每日一题2022):https://www.acwing.com/video/3876/

posted @ 2022-05-22 23:21  onlyblues  阅读(100)  评论(0编辑  收藏  举报
Web Analytics