CF2080C - Card Flip - XIX Open Olympiad in Informatics - Final Stage, Day 2

比赛难度挺高,但是很启发人的思维,这才是优质的题目,最终赛时只切了两道题,不过对我而言我觉得满足了。

C题

由题不难得出,双面牌要么改变牌组的奇偶性,要么不改变,也就是说,问题的关键在于双面牌。

只有一张双面牌的时候,我们容易看出,第一个拿到双面牌的人可以决定后面剩下的牌是奇数张还是偶数张,因此拿到这张双面牌的人一定胜利,而这张牌只由其前面有奇数或偶数张牌决定。

假设我们定义这样一张牌,如果被人拿到后,一定是胜利的,我们容易得出最后一张双面牌一定是最重要的 决胜牌 ,有且仅有前面的双面牌才可能改变拿到这张 决胜牌 的次序。

设最后一张牌是 \(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;
}
posted @ 2025-03-10 21:17  YipChip  阅读(48)  评论(0)    收藏  举报