首页 > 其他分享 >题解:P9137 [THUPC 2023 初赛] 速战速决

题解:P9137 [THUPC 2023 初赛] 速战速决

时间:2024-10-14 19:14:29浏览次数:5  
标签:cnt THUPC -- 题解 一张 初赛 张牌 ans push

Problem Link

[THUPC 2023 初赛] 速战速决

题目描述

题意清晰,不再过多赘述。

Solution

每张不同的卡是等效的。

小 \(J\) 手上的卡牌只有 \(2\) 种情况:手上没有相同的牌和有相同的牌。

情况 \(1\):

小 \(J\) 手上 的牌等价于 \(1 \sim n\)(但其实没用),令其手上的牌为 \(b_1, b_2,\ldots,b_n\)。

由于要“速战速决”,所以尽量让 \(J\) 少拿牌(这个在情况 \(2\) 中也适用),那么如何让 \(J\) 少拿牌呢?

因为手牌为排列,所以 \(I\) 手上每张牌 \(J\) 都有一张复制,同理 \(J\) 上每张牌 \(I\) 中也有一张复制。

前者的说法是因为 \(I\) 先手,垫下去的第一张牌一定会被 \(J\) 回收;后者是因为,只要第一张牌不被 \(J\) 回收,我们可以视为少 \(1\) 张牌+\(J\) 先手,如此除了放的第一张牌其他所有牌都能回收。

那么我们放的第一张牌就很显然了,即 \(b_n\),之后 \(J\) 每打一张牌,我们跟同一张,即可在 \(n\) 次后使得 \(J\) 手牌中是两张 \(b_n\),其他所有牌在 \(I\) 手上,此时轮到 \(I\) 先手,随便放一张牌 \(x\),待 \(J\) 打出 \(b_n\) 后再打出一张 \(x\),\(J\) 出完一张 \(b_n\) 后就会因无牌而败了。

综上,操作次数为 \(n+2\),操作序列为 \(b_n, b_1, b_2,\ldots, b_{n-1}, b_1, b_1\)。

情况 \(2\):

假设 \(J\) 将打出第 \(i\) 张牌和第 \(i+1\) 牌:

  • \(b_i\) 是一张单牌(即另一张牌 \(x = b_i\) 在 \(I\) 手上):打出 \(x\) 将其收回即可。

  • \(b_i\) 不是一张单牌但另一张牌 \(x = b_i\) 不是下一张被打出的牌:学习情况 \(1\) 中的策略,只要保证 \(b_i\) 的收回只能收 \(2\) 张即可。

  • \(b_i\) 不是一张单牌且 \(b_{i+1} = b_i\):在 \(J\) 下次打出 \(b_i\) 前提前垫一张不是单牌 \(x\),在其打出 \(b_i\) 后打出另一张 \(x\) 将 \(b_i\) 回收即可。

操作 \(1\) 等价于操作 \(1\) 次得 \(1\) 张牌,操作 \(2\) 等价于操作 \(2\) 次得 \(2\) 张牌,操作 \(3\) 等价于操作 \(2\) 次得 \(2\) 张牌,总共要从 \(J\) 处获得 \(n-1\) 张牌,所以要操作 \(n-1\) 次,算上第一次先手垫的 \(1\) 张牌,总操作数为 \(n\) 次。

代码实现就显然了。

代码

//written by Naught
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define Maxn 300005
#define fo(i, l, r) for (int i = l; i <= r; ++i)
#define fr(i, r, l) for (int i = l; i >= r; --i)
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21], *p1 = buf, *p2 = buf;
inline int read(int x=0, bool f=0, char c=getchar()) {for(;!isdigit(c);c=getchar()) f^=!(c^45);for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);return f?-x:x;}

int n, b[Maxn], cnt[Maxn], lst, ind[Maxn], s[Maxn], top, ans[Maxn];
queue<int> q;

void push(int x) {ind[s[++top] = x] = 1;}

void pop(int x)
{
    while(s[top] != x) ++cnt[s[top]], ind[s[top]] = 0, q.push(s[top--]);
    ++cnt[x], ind[x] = 0, q.push(x), --top;
}

int main()
{
    n = read();
    if(n == 1) return puts("-1"), 0;
    fo(i, 1, n) cnt[i] = 2;
    fo(i, 1, n) b[i] = read(), --cnt[b[i]];
    fr(i, 1, n) if(cnt[i] == 2) {lst = i; break;}
    fr(i, 1, n) fr(j, 1, cnt[i]-(lst == i)) q.push(i);

    if(lst == 0)
    {
        printf("%d\n%d ", n+2, b[n]);
        fo(i, 1, n-1) printf("%d ", b[i]);
        printf("%d %d", b[1], b[1]);
        return 0;
    }

    push(ans[0] = lst), --cnt[ans[0]];
    fo(i, 1, n-1)
    {
        push(b[i]);
        if(cnt[b[i+1]] || ind[b[i+1]]) pop(ans[i] = s[1]);
        else
        {
            if(q.front() == s[1]) q.push(s[1]), q.pop();
            if(ind[ans[i] = q.front()]) pop(ans[i]);
            else push(ans[i]), --cnt[ans[i]], q.pop();
        }
    }

    printf("%d\n", n);
    fo(i, 0, n-1) printf("%d ", ans[i]);

    return 0;
}

标签:cnt,THUPC,--,题解,一张,初赛,张牌,ans,push
From: https://www.cnblogs.com/naughty-naught/p/18464792

相关文章

  • 题解:P6299 差别
    ProblemLink差别题目描述给定\(a,b,c,d\),求\(p,q,r,s\)使得\(M\)成为非零最小值。Solution\(M\)的表达式很复杂,把式子拆开有\(16\)个\(4\)次项,不难发现这是一个平方和,不断套平方和公式,最后化简成:\[M=|(ap+bq+cr-ds)^2+(-aq+bp+cs+dr)^2|=((a+bi)\times(......
  • 题解:P9743 「KDOI-06-J」旅行
    ProblemLink「KDOI-06-J」旅行题意题目讲的很清楚,不再过多赘述。Solution不难想到\(O(n^2\timesm^2\timesk)\)的做法:定义\(f_{i,j,val,x,y}\)为当前在\((x,y)\)的位置,花费\(val\)元,手上有\(x\)张\(L\)公司的票,\(y\)张\(Z\)公司的票的方案数,至于空间问题......
  • 题解:P1709 [USACO5.5] 隐藏口令 Hidden Password
    ProblemLink[USACO5.5]隐藏口令HiddenPassword题目描述求最小表示法的开头字母在原字符串的位置。Solution最小表示法板子,双指针解决即可。Code#include<iostream>#include<algorithm>#include<string.h>#include<cstring>#include<cmath>#include<cstdio>......
  • [PA2021] Od deski do deski 题解
    好题好题,难者不会会者不难,我是前者。实际上加入就可以合法的数是很好计算的。考虑现在所有前缀合法串后的字符实际上都可以满足条件。容易想到根据是否合法设置状态。设\(f_{i,j}/g_{i,j}\)表示现在填第\(i\)个数,有\(j\)个填了就合法的数,现在的串合法/不合法。那么有转......
  • 题解:P11145 Strange Homura Game
    ProblemLinkStrangeHomuraGame题意让你猜测一个数\(n\),你只能输出两次,每次输出一个数\(x\),返回\(x\bmodn\)。Solution令输入的数为\(A,B\),输出的数为\(a,b\),答案为\(n\)。一开始想的是CRT,但只能询问\(2\)次。发现输入的值是经过\(\bmodn\)的,已知\((A-a)......
  • 题解:AT_joi2021ho_b 雪玉 (Snowball)
    ProblemLink[JOI2021Final]雪玉题目描述翻译很简洁,不作赘述。Solution对于相邻的两个雪球\(a_i\)和\(a_{i+1}\),两者夹着的区间中的雪要么是被\(a_i\)或\(a_{i+1}\)卷起,要么不可能被清理掉。那么思路非常简单了,对于每个区间,只有\(2\)种情况:区间左侧雪球的最......
  • 题解:P2315 [HNOI2005] 数三角形
    ProblemLink[HNOI2005]数三角形题意输入一个大三角形的各个边存在情况,输出里面有多少个正三角形。Solution简单暴力即可,用\(4\)个数组维护每条边能延伸的最大长度,然后逐个判断三角形是否可行即可。如图,l_upper维护左端点向上(即$\ell_{BA}$),l_lower维护左端点向下(即......
  • 题解:AT_arc120_c [ARC120C] Swaps 2
    ProblemLink[ARC120C]Swaps2\(-1\)的情况判错卡了\(10\)几分钟,麻了。题面翻译给出\(2\)个序列\(a\)和\(b\),定义一次操作为:选定一个下标\(i\),先将\(a_i\)以及\(a_{i+1}\)交换,然后让\(a_i\)加一,最后让\(a_{i+1}\)减一。求最少操作次数使得\(a\)序列等......
  • 题解:[HNOI2009] 双递增序列
    ProblemLink[HNOI2009]双递增序列题目描述给定一个长度为\(n\)的序列(\(n\)为偶数),求是否可以把序列分成\(2\)个长度为\(\frac{n}{2}\)的递增序列。Solution首先想到定义\(f_i\)为一个序列以\(a_i\)结尾时另一个序列末尾最小值。但这样定义状态信息是不够的,考虑......
  • qoj6562 First Last 题解
    妙妙题。首先不同字母数最多为\(3\)。我们把每一个字母看成一个点。对于每一个字符串,首个字母朝末尾字母连一条有向边。那么问题变为了给定一张有向图,从某个点出发,每次走一条边,且边不能重复,不能走的人输。问哪方有必胜策略。先不考虑时间复杂度,那么这个可以直接爆搜。但是肯定......