[ARC104] C - Fair Elevator
题面
题目大意
有 \(2n\) 个楼层和一部从 \(1\) 层到 \(2n\) 层单向运行一次的电梯。\(n\) 个人,第 \(i\) 个人会在 \(a_i\) 层上,\(b_i\) 层下。现有若干个值丢失,查询是否存在重新填数的方式使得:
-
\(a\) 和 \(b\) 共同构成长为 \(2n\) 的排列。
-
\(\forall 1\leq i,j\leq n,[a_i,b_i]\cap [a_j,b_j]\neq \emptyset\),有 \(b_i-a_i=b_j-a_j\)。
数据范围
- \(1\leq n\leq 100\)。
题解
首先,最后的方式肯定是由若干个不交的段组成,每段前半部分有人上,后半部分全下。
那么我们可以预处理并线性判断一个区间作为一个段是否合法。
接下来对数轴做可行性 DP 即可,时间复杂度 \(O(n^3)\)。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=2e2+9;
int f[N],a[N],b[N],op[N],id[N],n;
inline bool Check(int l,int r){
int len=r-l+1,mid=l+r>>1,hf=len>>1;
if(len&1) return 0;
for(int i=l;i<=mid;i++){
if(!id[i]) continue ;
if(op[i]==0){
if(b[id[i]]!=-1&&b[id[i]]!=i+hf) return 0;
else if(b[id[i]]==-1&&id[i+hf]) return 0;
}else return 0;
}
for(int i=mid+1;i<=r;i++){
if(!id[i]) continue ;
if(op[i]==1){
if(a[id[i]]!=-1&&a[id[i]]!=i-hf) return 0;
else if(a[id[i]]==-1&&id[i-hf]) return 0;
}else return 0;
}
return 1;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
for(int i=1;i<=n;i++){
if(a[i]!=-1){
if(id[a[i]]){
cout<<"No"<<endl;
return 0;
}
op[a[i]]=0,id[a[i]]=i;
}
if(b[i]!=-1){
if(id[b[i]]){
cout<<"No"<<endl;
return 0;
}
op[b[i]]=1,id[b[i]]=i;
}
}
f[0]=1;
for(int i=1;i<=(n<<1);i++){
for(int j=1;j<=i;j++) f[i]|=f[j-1]&Check(j,i);
}
if(f[n<<1]) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}

浙公网安备 33010602011771号