【洛谷P8866】喵了个喵

1|0题目


题目链接:https://www.luogu.com.cn/problem/P8866
小 E 喜欢上了一款叫做《喵了个喵》的游戏。这个游戏有一个牌堆和 n 个可以从栈底删除元素的栈,任务是要通过游戏规则将所有的卡牌消去。开始时牌堆中有 m 张卡牌,从上到下的图案分别是 a1,a2,,am。所有的卡牌一共有 k 种图案,从 1k 编号。牌堆中每一种图案的卡牌都有偶数张。开始时所有的栈都是空的。这个游戏有两种操作:

  • 选择一个栈,将牌堆顶上的卡牌放入栈的顶部。如果这么操作后,这个栈最上方的两张牌有相同的图案,则会自动将这两张牌消去。
  • 选择两个不同的栈,如果这两个栈栈的卡牌有相同的图案,则可以将这两张牌消去,原来在栈底上方的卡牌会成为新的栈底。如果不同,则什么也不会做。

这个游戏一共有 T 关,小 E 一直无法通关。请你帮小 E 设计一下游戏方案,即对于游戏的每一关,给出相应的操作序列使得小 E 可以把所有的卡牌消去。

n300,m2×106,k{2n2,2n1}

2|0思路


首先 k=2n2 的很好做,每一个元素与其前/后一个相同元素匹配,把至多两个元素放在一个栈中,消除的时候在栈顶就直接放到栈里,在栈底就放在最后一个空栈里。
k=2n1 的时候,可能出现 n1 个栈都放了两个元素,但是下一个元素不存在于任何栈中的情况。无论是将这个元素放在最后一个栈,或是任意一个已经放了两个元素的栈中,都可能导致无法消除。
假设一个有两个元素的栈,栈底为 x,栈顶为 y,观察到,如果将这最后一个元素 z 放在这个栈上面,若在牌堆中下一个 x 出现的比下一个 y 早,那么其实不会有任何的影响。因为利用最后一个空栈将 x 消除后,又会变为原来的情况。
如果所有栈都不满足下一个 x 出现的比下一个 y 早,那么只需要将 z 放在那个空栈中,然后把 nx 中在牌堆中最早出现的那一个所在的栈设为新的空栈即可。因为这一个 x 一定可以通过操作 1 来消除。
需要注意的是,当一个栈被定义为“空栈”的时候,无论那个栈是否还存在元素,都不可以往里面再添加元素,直到下一次特殊情况出现。否则可能导致因为加入新的元素,这个栈底无法通过操作 1 来消除。
实现的话我比较无脑,直接维护 4set,分别储存 有 0 个元素(注意不等价于上文的“空栈”,那个“空栈”是用来处理特殊情况的空栈) / 1 个元素 / 2 个元素且 x 先于 y / 2 个元素且 x 后于 y 的栈的编号。注意“空栈”需要特殊记下来。
时间复杂度 O(mlogn)

3|0代码


#include <bits/stdc++.h> #define mp make_pair #define fi first #define se second using namespace std; const int N=610,M=2000010; int Q,n,m,k,pos,a[M],bel[N],st[N][4]; queue<pair<int,int> > q; set<int> s0,s1,s2,s3; vector<int> nxt[N]; int main() { scanf("%d",&Q); while (Q--) { s0.clear(); s1.clear(); s2.clear(); s3.clear(); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=m;i++) scanf("%d",&a[i]); for (int i=m;i>=1;i--) nxt[a[i]].push_back(i); for (int i=2;i<=n;i++) s0.insert(i); pos=1; for (int i=1;i<=m;i++) { nxt[a[i]].pop_back(); int p=bel[a[i]]; if (!p) { if (s0.size()) { int id=*s0.begin(); q.push(mp(id,-1)); s1.insert(id); s0.erase(s0.begin()); st[id][1]=a[i]; bel[a[i]]=id; } else if (s1.size()) { int id=*s1.begin(); if (id==pos) id=*(++s1.begin()); q.push(mp(id,-1)); s1.erase(s1.find(id)); if (nxt[st[id][1]].back()>nxt[a[i]].back()) s2.insert(id); if (nxt[st[id][1]].back()<nxt[a[i]].back()) s3.insert(id); st[id][2]=a[i]; bel[a[i]]=id; } else if (s3.size()) { int id=*s3.begin(); q.push(mp(id,-1)); st[id][3]=a[i]; bel[a[i]]=id; } else { q.push(mp(pos,-1)); s1.insert(pos); st[pos][1]=a[i]; bel[a[i]]=pos; for (int j=i+1;j<=m;j++) if (st[bel[a[j]]][1]==a[j]) { pos=bel[a[j]]; break; } } } else if (st[p][1]==a[i] && !st[p][2]) { q.push(mp(p,-1)); s1.erase(s1.find(p)); st[p][1]=0; bel[a[i]]=0; if (p!=pos) s0.insert(p); } else if (st[p][2]==a[i]) { q.push(mp(p,-1)); s1.insert(p); s2.erase(s2.find(p)); st[p][2]=0; bel[a[i]]=0; } else if (st[p][3]==a[i]) { q.push(mp(p,-1)); st[p][3]=0; bel[a[i]]=0; } else if (st[p][1]==a[i] && st[p][2]) { q.push(mp(pos,-1)); q.push(mp(pos,p)); if (!st[p][3]) { s1.insert(p); s3.erase(s3.find(p)); st[p][1]=st[p][2]; st[p][2]=0; } else { if (nxt[st[p][2]].back()>nxt[st[p][3]].back()) s2.insert(p),s3.erase(s3.find(p)); st[p][1]=st[p][2]; st[p][2]=st[p][3]; st[p][3]=0; } bel[a[i]]=0; } } printf("%d\n",(int)q.size()); for (;q.size();q.pop()) { pair<int,int> res=q.front(); if (res.se==-1) printf("1 %d\n",res.fi); if (res.se!=-1) printf("2 %d %d\n",res.fi,res.se); } } return 0; }

__EOF__

本文作者stoorz
本文链接https://www.cnblogs.com/stoorz/p/16943135.html
关于博主:菜死了 /fad
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   stoorz  阅读(286)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-12-01 【洛谷P3579】PAN-Solar Panels
2020-12-01 【洛谷P3261】城池攻占
2020-12-01 【YbtOJ#20236】红点蓝点
2020-12-01 【YbtOJ#20235】公共序列
点击右上角即可分享
微信分享提示