CF2080C - Card Flip - XIX Open Olympiad in Informatics - Final Stage, Day 2
比赛难度挺高,但是很启发人的思维,这才是优质的题目,最终赛时只切了两道题,不过对我而言我觉得满足了。
由题不难得出,双面牌要么改变牌组的奇偶性,要么不改变,也就是说,问题的关键在于双面牌。
只有一张双面牌的时候,我们容易看出,第一个拿到双面牌的人可以决定后面剩下的牌是奇数张还是偶数张,因此拿到这张双面牌的人一定胜利,而这张牌只由其前面有奇数或偶数张牌决定。
假设我们定义这样一张牌,如果被人拿到后,一定是胜利的,我们容易得出最后一张双面牌一定是最重要的 决胜牌 ,有且仅有前面的双面牌才可能改变拿到这张 决胜牌 的次序。
设最后一张牌是 \(a \to b\),表示正面为 \(a\),反面为 \(b\),有一张双面牌 \(c \to d\) 满足 \(c < a\) 即在最后一张牌前面,那么有两种情况:
-
这张双面牌不会决定胜利,也就是说,我无论删除还是翻面,都不影响 \(a\) 的位置,也就是说 \(a < d\),这样的牌无意义。
-
这张双面牌会决定胜利,也就是说 \(d < a\),我删除和翻面可以改变牌组之后的奇偶性,以此来让我能拿到后面的决胜牌,因此这张牌才是我真正的决胜牌。
如上,我们发现这个定义可以递归回去,找到第一张符合条件的 决胜牌 后,数一数前面有几张牌即可,如果是偶数,先手必胜,否则后手必胜。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
int c[N];
struct Segment {
int a, b;
}flip[N];
bool cmp(Segment x, Segment y) {
return x.a > y.a;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
int cnt = 0, last = 0;
for (int i = 1; i <= n; i ++ ) cin >> flip[i].a;
for (int i = 1; i <= n; i ++ ) cin >> flip[i].b;
for (int i = 1; i <= m; i ++ ) cin >> c[i];
sort(flip + 1, flip + n + 1, cmp);
for (int i = 1; i <= n; i ++ ) {
if (!last) last = i;
else if (flip[i].b < flip[last].a) last = i;
}
for (int i = 1; i <= m; i ++ ) {
if (c[i] < flip[last].a) {
cnt ++ ;
}
}
cnt += n - last;
if (cnt & 1) cout << "Second\n";
else cout << "First\n";
return 0;
}