P8866 [NOIP2022] 喵了个喵 (构造)
构造模拟题,思路很简洁,但是代码不好写。
首先看到数据范围,发现
#
观察两种操作,对于即将进入的牌
- 把所有栈的数量控制在
以内是最优的,并且所有相同类型的牌不会在栈中出现第二次。 - 当某类牌出现偶数次时,会被消光。
再回到数据范围,如果我们将
#
我们仍然想要沿用之前的思路,但是会遇到新的情况,即前
这时我们考虑什么时候不能放在空栈。发现如果放在空栈,当遇到一个目前类型在栈底的牌,并且此时它仍被栈顶挡住时,就无解了;如果两张
设栈
如果
如果
现在思路就清晰了:
能用先前的思路就用先前的思路,不能用就分类讨论。
代码能力在这里就体现了,如果没有运用合适的数据结构就会写的很复杂。
- 对于可用的位置我们用队列维护,原先每个栈放两个位置进去。
- 对于栈,我们用双端队列维护,我们还需要每个种类的牌此时所在的位置,用数组
记录。 - 对于答案记录,边模拟边记录,数组或 vector 都可以。
- 由于操作会多次调用,所以考虑用函数封装,使主函数代码更简洁。
每一次枚举找到第一个在类型在栈底的牌后,我们可以直接将
总结:一题有思维的模拟题,需要从数据范围出发,找到启发性性质,对模拟过程有清晰思路后才开始写代码;用合适的数据结构维护数据和模拟过程。
#include <bits/stdc++.h>
typedef std::pair<int, int> pii;
typedef long long ll;
int read() {
int x = 0, f = 1;
char c = getchar();
while(!isdigit(c)) {
if(c == '-') f = -1;
c = getchar();
}
while(isdigit(c)) {
x = (x << 3) + (x << 1) + (c - '0');
c = getchar();
}
return x * f;
}
int t, n, m, k, sp;
int a[2000010], id[610];
std::deque<int> st[610];
std::vector<pii> ans;
std::queue<int> q;
void pu(int x) {
ans.push_back({0, x});
}
void del(int x, int y) {
ans.push_back({x, y});
}
bool normal(int a) {
int s = id[a];
if(!s) {
if(q.empty()) return 0;
s = q.front();
q.pop();
pu(s);
st[s].push_back(a);
id[a] = s;
}
else {
id[a] = 0;
q.push(s);
if(st[s].back() == a) {
pu(s);
st[s].pop_back();
}
else {
pu(sp);
del(s, sp);
st[s].pop_front();
}
}
return 1;
}
void Solve() {
memset(id, 0, sizeof(id));
while(!q.empty()) q.pop();
ans.clear();
n = read(), m = read(), k = read();
sp = n;
for(int i = 1; i <= m; i++) a[i] = read();
for(int i = 1; i < n; i++) {
q.push(i), q.push(i);
}
for(int i = 1; i <= m; i++) {
if(!normal(a[i])) {
int r = i + 1, x = a[r], now = a[i];
for(; r <= m && x != now && st[id[x]].back() == x; r++, x = a[r]);
if(x == now) {
pu(sp);
for(int l = i + 1; l < r; l++) {
normal(a[l]);
}
pu(sp);
}
else {
bool flg = 0;
int s = id[x], y = st[s].back();
for(int l = i + 1; l < r; l++) {
if(a[l] == y) {
flg ^= 1;
}
}
if(!flg) {
pu(s);
st[s].push_back(now);
for(int l = i + 1; l < r; l++) {
if(a[l] == y) pu(sp);
else normal(a[l]);
}
pu(sp);
del(s, sp);
st[s].pop_front();
id[x] = 0;
id[now] = s;
}
else {
pu(sp);
st[sp].push_back(now);
for(int l = i + 1; l < r; l++) {
if(a[l] == y) pu(s);
else normal(a[l]);
}
pu(s);
id[x] = id[y] = 0;
id[now] = sp;
st[s].clear();
q.push(sp);
sp = s;
}
}
i = r;
}
}
std::cout << ans.size() << "\n";
for(pii p : ans) {
if(p.first == 0) std::cout << "1 " << p.second << "\n";
else std::cout << "2 " << p.first << " " << p.second << "\n";
}
}
int main() {
t = read();
while(t--) Solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具