sol of P8866 [NOIP2022] 喵了个喵
披着构造外衣的大模拟。
本来想练习一下构造题,30 分钟糊出来了一个构造方案,以为做完了,没想到只是痛苦写代码和调试过程的开始。。。还好考场上没有想出来怎么构造,不然怕一等奖都拿不到
猜想有一个很强的性质:可以实现在一个局面中,每种牌至多只有一张。也就是说,如果一张牌在序列中是这种牌的第偶数次出现,那么它一定是用来消除局面中之前加入的牌的。
时显然可以随便做。在这个做法的基础上分析当加入一张牌时,局面中总共有 张牌怎么办,即可推导出构造过程。
构造过程的伪代码如下。
When dealing with the -th card:
- If the mode is normal:
- If the card is to add and there will be kinds of cards, switch the mode into alert.
- Otherwise, move as normal.
- If the mode is alert:
- If there is a stack that the card on its top won't be removed before removing the -th card or removing the card at its bottom, put the -th card on its top. Then keep moving as normal (because there is only kinds of cards and stacks). After that, switch the mode to normal.
- Otherwise, put the -th card into the empty stack, switch the mode to easy, record the card at bottom which is the first to remove.
- If the mode is easy:
- If the -th card is to remove a card in the bottom, do it and switch the mode to normal.
- Move as normal but make sure that the stack with the first card in the bottom to be removed will be operate at most once.
大概调试了六个小时的样子(?),得出了最终代码(里面还有很多写法是为了调试方便)
#include<bits/stdc++.h>
using namespace std;
constexpr int N=605,M=2e6+5;
int n,m,K,a[M],pos[N],nxt[M],cnt,mb[N],mt[N],mode,te;
bool ise[N],isu[N];
vector<pair<int,int>>op;
set<int>st,sb;queue<int>qe,qu;
/*
void debug(){
int xcnt=0;
for(int j=1;j<=n;j++){
printf("mb[%d]=%d,mt[%d]=%d,ise[%d]=%d\n",j,mb[j],j,mt[j],j,ise[j]);
xcnt+=(!!mb[j])+(!!mt[j]);
}
assert(xcnt==cnt||(cnt==n*2-1&&xcnt==cnt-1));
}
*/
void move(int i){
//printf("MOVE: cnt=%d,i=%d,te=%d,mode=%d\n",cnt,i,te,mode);
//debug()
if(sb.size()&&i==*sb.begin())sb.erase(sb.begin());
if(nxt[i]){
while(qe.size()&&!ise[qe.front()])qe.pop();
//if(qe.empty())debug();
//assert(qe.size());
int k=qe.front();
op.emplace_back(k,0);// STACK k has been changed!
cnt++;
if(mb[k]){// put on the top
ise[k]=0;
mt[k]=nxt[i];
pos[a[i]]=k;
st.insert(mt[k]);
if(mt[k]>mb[k]){
qu.push(k);isu[k]=1;
}
}else{// put on the bottom
sb.insert(mb[k]=nxt[i]);
pos[a[i]]=k;
}
}else{
cnt--;
if(mb[pos[a[i]]]==i){
int k=pos[a[i]];
if(mt[k]){
op.emplace_back(te,0);
op.emplace_back(k,te);// STACK k has been changed!
if(mt[k]>mb[k])isu[k]=0;
st.erase(mt[k]);
sb.erase(mb[k]);
sb.insert(mb[k]=mt[k]);
mt[k]=0;
if(k!=mode){
ise[k]=1;
qe.push(k);
}
}else{
op.emplace_back(k,0);
sb.erase(mb[k]);
mb[k]=0;
}
}else{
int k=pos[a[i]];
op.emplace_back(k,0);// STACK k has been changed!
if(mt[k]>mb[k])isu[k]=0;
st.erase(mt[k]);
mt[k]=0;
if(k!=mode){
ise[k]=1;
qe.push(k);
}
}
}
}
void work(int&i){
//printf("WORK %d\n",i);
int k=0;
while(qu.size()&&!isu[qu.front()])qu.pop();
if(qu.size())k=qu.front();else{
auto p=st.upper_bound(nxt[i]);
if(p!=st.end())k=pos[a[*p]];
}
if(!k){
op.emplace_back(te,0);
qe.push(te);// STACK te has been changed!
ise[te]=1;sb.insert(mb[te]=nxt[i]);
//printf("sb.insert %d\n",mb[te]);
cnt++;pos[a[i]]=te;te=0;
ise[mode=pos[a[*sb.begin()]]]=0;// MODE is WRONG!
//printf("when i=%d, k=0, mode=%d, *sb.begin()=%d\n",i,mode,*sb.begin());
//debug();
return;
}
int p=nxt[i],ed=min(p,mb[k]);
op.emplace_back(k,0);cnt++;// STACK k has been changed!
for(i++;i<ed;i++)move(i);
if(ed==mb[k]){
//puts("point 1");
isu[k]=0;
st.erase(mt[k]);
sb.erase(mb[k]);
sb.insert(mb[k]=mt[k]);
st.insert(mt[k]=p);
pos[a[mt[k]]]=k;
pos[a[mb[k]]]=k;
if(mt[k]>mb[k])isu[k]=1;
op.emplace_back(te,0);
op.emplace_back(k,te);// STACK k has been changed!
cnt--;
}else{
//puts("point 2");
op.emplace_back(k,0);
cnt--;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;cin>>T;while(T--){
op.clear();st.clear();
memset(mb,0,sizeof(mb));
memset(mt,0,sizeof(mt));
memset(isu,0,sizeof(isu));
sb.clear();
while(qe.size())qe.pop();
while(qu.size())qu.pop();
cin>>n>>m>>K;te=n;
for(int i=1;i<n;i++){
qe.push(i);
ise[i]=1;
}
ise[n]=0;
memset(pos,0,sizeof(pos));
for(int i=1;i<=m;i++){
nxt[i]=0;
cin>>a[i];
if(pos[a[i]]){
nxt[pos[a[i]]]=i;
pos[a[i]]=0;
}else pos[a[i]]=i;
}
mode=0;cnt=0;
for(int i=1;i<=m;i++){
if(!mode){
if(nxt[i]&&cnt==n*2-2)work(i);
else move(i);
}else{
if(!nxt[i]&&mb[pos[a[i]]]==i){
int k=pos[a[i]];
//assert(mode==k);
op.emplace_back(k,0);// STACK k has been changed!
te=k;mode=0;cnt--;ise[te]=0;
mt[k]=mb[k]=0;sb.erase(sb.begin());
//printf("SWITCH: cnt=%d,i=%d,te=%d\n",cnt,i,te);
//debug();
}else move(i);
}
}
printf("%lu\n",op.size());
for(auto p:op){
if(p.second)printf("2 %d %d\n",p.first,p.second);
else printf("1 %d\n",p.first);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现