题解:P17274 [eJOI 2026] Elevator
lailai0916 · · 题解
题意简述
电梯从第
每名被访问的住户知道当前按钮集合和自己的值。住户只能按下更高楼层的按钮。到达屋顶后,需要仅根据最终按钮集合恢复尽量多的住户值。
解题思路
设最终按下的按钮集合为
把
这些位置就是住户被访问的顺序。电梯停在
后面的构造把若干连续按钮分成编码块。访问序号决定当前使用哪个编码块。码字中每个
子任务一
在第
- 若
v_i=1 ,按下i+1 ; - 若
v_i=0 ,按下i+2 。
超出第
对所有
子任务二
先按下按钮
设这两个值依次为
第二次访问该组时,根据
| 码字 | ||
|---|---|---|
四个码字互不相同,并且都至少包含两个
第
前
子任务三
对
| 码字 | |
|---|---|
三个码字互不相同,并且都至少包含一个
处理
子任务四
先按下按钮
设这两个值依次为
表中
第
前
正确性证明
先证明所有按键操作均合法。各编码区间互不相交,且每个新区间都位于对应编码者上方。辅助函数 put 还会排除已经按下的按钮。因此,返回的按钮编号均严格大于当前楼层,且不会重复。
子任务二和四的每个完整码字分别至少包含两个和三个
对于子任务一,按钮
对于子任务二,每组的四种
对于子任务三,三种取值对应三个不同码字。屋顶读取每组的两个按钮后,可以唯一恢复该组表示的值。
对于子任务四,每组的十六种
综上,四个计分子任务能恢复的值数依次为
参考代码
#include <bits/stdc++.h>
#include "elevator.h"
using namespace std;
const int key2[2]={2,0};
const int code2[2][2]={{5,6},{3,7}};
const int code3[3]={3,1,2};
const int key4[4]={4,3,2,1};
const int code4[4][4]={{19,21,22,23},{11,13,14,25},{7,15,28,29},{26,27,30,31}};
vector<int> put(int s,int n,int m,const vector<int> &p)
{
vector<int> q;
for(int i=0;i<n;i++)
{
if((m>>i&1)&&!binary_search(p.begin(),p.end(),s+i))q.push_back(s+i);
}
return q;
}
vector<int> press1(int f,int v)
{
int x=f+2-v;
if(x<=60)return {x};
return {};
}
vector<int> press2(int f,int v,const vector<int> &p)
{
if(!f)return {1,2+key2[v]};
int j=upper_bound(p.begin(),p.end(),f)-p.begin();
if(j>=40)return {};
if(j>=38)
{
if(v)return {j+21};
return {};
}
int s=j/2*3+2;
if(j%2==0)return {s+key2[v]};
int x=binary_search(p.begin(),p.end(),s+key2[0])?0:1;
return put(s,3,code2[x][v],p);
}
vector<int> press3(int f,int v,const vector<int> &p)
{
int j=upper_bound(p.begin(),p.end(),f)-p.begin();
if(j>=30)return {};
int s=j*2+1;
return put(s,2,code3[v],p);
}
vector<int> press4(int f,int v,const vector<int> &p)
{
if(!f)return {1,2+key4[v]};
int j=upper_bound(p.begin(),p.end(),f)-p.begin();
if(j>=25)return {};
if(j>=16)
{
int s=(j-16)*2+42;
return put(s,2,v,p);
}
int s=j/2*5+2;
if(j%2==0)return {s+key4[v]};
int x=0;
while(!binary_search(p.begin(),p.end(),s+key4[x]))x++;
return put(s,5,code4[x][v],p);
}
vector<int> answer1(const vector<int> &p)
{
vector<int> q(61);
for(auto x:p)q[x-1]=1;
q[60]=1;
return q;
}
vector<int> answer2(const vector<int> &p)
{
vector<int> a={0};
vector<int> b(61);
vector<int> q(61,-1);
for(auto x:p)
{
a.push_back(x);
b[x]=1;
}
for(int i=0;i<19;i++)
{
int s=i*3+2,m=0,x=0,y=0;
for(int j=0;j<3;j++)m|=b[s+j]<<j;
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
if(code2[j][k]==m)x=j,y=k;
}
}
q[a[i*2]]=x;
q[a[i*2+1]]=y;
}
q[a[38]]=b[59];
q[a[39]]=b[60];
return q;
}
vector<int> answer3(const vector<int> &p)
{
vector<int> a={0};
vector<int> b(61);
vector<int> q(61,-1);
for(auto x:p)
{
a.push_back(x);
b[x]=1;
}
for(int i=0;i<30;i++)
{
int m=b[i*2+1]+b[i*2+2]*2;
q[a[i]]=find(code3,code3+3,m)-code3;
}
return q;
}
vector<int> answer4(const vector<int> &p)
{
vector<int> a={0};
vector<int> b(61);
vector<int> q(61,-1);
for(auto x:p)
{
a.push_back(x);
b[x]=1;
}
for(int i=0;i<8;i++)
{
int s=i*5+2,m=0,x=0,y=0;
for(int j=0;j<5;j++)m|=b[s+j]<<j;
for(int j=0;j<4;j++)
{
for(int k=0;k<4;k++)
{
if(code4[j][k]==m)x=j,y=k;
}
}
q[a[i*2]]=x;
q[a[i*2+1]]=y;
}
for(int i=16;i<25;i++)
{
int s=(i-16)*2+42;
q[a[i]]=b[s]+b[s+1]*2;
}
return q;
}
vector<int> press_buttons(int subtask,int,int f,int v,vector<int> p)
{
if(subtask==1)return press1(f,v);
if(subtask==2)return press2(f,v,p);
if(subtask==3)return press3(f,v,p);
if(subtask==4)return press4(f,v,p);
return {};
}
vector<int> answer(int subtask,int,vector<int> p)
{
if(subtask==1)return answer1(p);
if(subtask==2)return answer2(p);
if(subtask==3)return answer3(p);
if(subtask==4)return answer4(p);
return vector<int>(61,-1);
}