1 条题解

  • 0
    @ 2025-8-24 22:45:43

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Yikuwa
    as the moon,so beautiful

    搬运于2025-08-24 22:45:43,当前版本为作者最后更新于2023-03-07 23:30:37,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    我们将小 I 的初始手牌分为两种情况:手中有两张相同的牌或没有。

    容易发现后者等价于小 I 手中的牌为一个 11nn 的排列,这种情况下由于小 I 打出的第一张牌的另一半一定在小 J 手上,所以小 J 至少能够收回一次牌。

    我们猜测小 I 存在一种方法能够使得小 J 只收回一次牌且收回牌数为 22,构造简单:

    题目给出小 J 的出牌顺序 :a1,a2,a3,...an,an,an:a_1,a_2,a_3,...a_n,a_n,a_n

    小 I 的出牌方法 :an,a1,a2,a3,...,an1,a1,a1:a_n,a_1,a_2,a_3,...,a_{n-1},a_1,a_1

    解释 :先打 ana_n,之后 n1n-1 轮打小 J 上一轮打出的牌,这样 nn 轮之后小 J 手上只剩两张 ana_n,小 I 连着打两张相同的牌即可。

    这样我们就做完了初始手牌为排列的情况。

    接下来处理小 I 手中存在两张相同的牌的情况,设小 I 初始手中有两张编号为 kk 的牌。

    我们考虑先打其中一张 kk,接下来时刻保持小 I 手中存在一张牌与牌堆底部的牌编号相同,这样的好处就是我们可以在每一次小 J 可能收牌前把牌堆抽完,保证小 J 收不到牌,从而在 nn 轮交换后结束游戏。

    考虑如何维护,不妨设当前牌堆底部牌为 xx,小 I 手中有另一张 xx,小 J 下一张要打的牌为 yy

    分情况讨论:

    • 另一张 yy 在牌堆中,此时如果不及时将牌堆中的 yy 收回,下一轮小 J 打出的 yy 就能形成收牌操作,所以此时小 I 打出 xx 清空牌堆,将牌堆中的 yy 收在手上,同时保证了下一回合小 J 打出 yy 后新牌堆顶 yy 的另一张在小 I 手中。

    • 另一张 yy 在小 I 手上,这种情况其实可收可不收,但是为了方便,我们同第一种情况打出 xx 收回整个牌堆,同样保证新牌堆顶 yy 的另一张在小 I 手中。

    • 另一张 yy 在小 J 手上,此时小 I 随便打一张牌就可以了,但是注意不能把手中与牌堆顶相同的那张牌打出去。

    至此,我们已经做完了这道题,具体在代码中,我们需要维护牌堆和记录每个牌的位置(是否在小 I 手中和是否在牌堆中),为了方便处理可以维护小 I 的手牌。写起来有些细节。

    #include<bits/stdc++.h>
    #define reg register
    #define IL inline
    using namespace std;
    //#define getchar() (_S==_T&&(_T=(_S=_B)+fread(_B,1,1<<15,stdin),_S==_T)?EOF:*_S++)
    char _C,_B[1<<15],*_S=_B,*_T=_B;
    IL int read(){
        reg int x=0,y=1;
        for(_C=getchar();!isdigit(_C);_C=getchar())if(_C=='-')y=-1;
        for(;isdigit(_C);_C=getchar())x=(x<<1)+(x<<3)+(_C^48);
        return x*y;
    }
    const int N=3e5+7;
    int n,cnt[N],a[N],in[N],s[N],top,Ans[N];
    queue<int>q;
    IL void Push(reg int x){in[s[++top]=x]=1;}
    IL void Pop(reg int x){
        while(s[top]!=x)++cnt[s[top]],in[s[top]]=0,q.push(s[top--]);
        ++cnt[x],in[x]=0,q.push(x),--top;
    }
    
    
    IL int work(){
        printf("%d\n%d ",n+2,a[n]);
        for(reg int i=1;i<n;++i)printf("%d ",a[i]);
        printf("%d %d",a[1],a[1]);
        return 0;
    }
    
    
    signed main(){
        for(reg int i=n=read();i;--i)cnt[i]=2;
        if(n==1)return !puts("-1");
        for(reg int i=1;i<=n;++i)--cnt[a[i]=read()];
        reg int Start=0;
        for(reg int i=n;i&&!Start;--i)if(cnt[i]==2)Start=i;
        for(reg int i=n;i;--i)for(reg int j=cnt[i]-(Start==i);j;--j)q.push(i);
        
        if(!Start)return work();
        
        Push(Ans[0]=Start),--cnt[Ans[0]];
        for(reg int i=1;i<n;++i){
            Push(a[i]);
            if(cnt[a[i+1]]||in[a[i+1]]){
                Pop(Ans[i]=s[1]);
            }
            else{
                q.front()==s[1]?q.push(s[1]),q.pop():void();
                if(in[Ans[i]=q.front()]){
                    Pop(Ans[i]);
                }
                else{
                    Push(Ans[i]),--cnt[Ans[i]];
                    q.pop();
                }
            }
        }
        printf("%d\n",n);
        for(reg int i=0;i<n;++i)printf("%d ",Ans[i]);
        return 0;
    }
    
    • 1

    信息

    ID
    8471
    时间
    1000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者