ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UOJ #408. 【IOI2018】机械娃娃

2022-06-26 12:35:48  阅读:136  来源: 互联网

标签:IOI2018 rs int MN len 开关 二叉树 UOJ 408


同为LOJ 2866

题目叙述

一共有 \(n\) 个触发器,每个触发器可以走到另一个器件。还有若干个开关,每个开关有两种出口。还有一个起点。
现在有一个球从起点出发,沿着线路走。开关有两种状态X和Y,如果在状态X必须走第一个出口,否则走第二个。一个开关被走一次之后会切换状态。现在 \(n\) 个触发器的经过顺序规定(可能重复),请给出构造使得满足这个条件。开关数量不能超过 \(n+\log_2 n\)

题解

一个开关有两个叉,而且只有开关有分叉。所以必须通过开关来实现触发器需要重复这件事情。
为什么是两个叉,是因为实际上题目想要你构造一个二叉树。但好像这题改成三叉树也可以。
考虑一颗完美二叉树,每个叶子节点连接根。可以发现,这样遍历叶子顺序是按照 \(rev_i\) 遍历的。但是最坏情况下,二叉树节点数量大概是 \(2n\) 。
考虑优化。发现一个节点如果两个子树内一个叶子都没有,那么直接让这个节点链接根即可。

反思

一般来说构造题会给很大的自由度给我们造成迷惑。因此应当自己限定一下构造的东西。比如构造一棵二叉树。另外时常思考一下剪枝。还有信息的重复利用。

代码

#include "doll.h"
#include <algorithm>
#include <iostream>
using namespace std;
const int MN=2e5+5;
int ls[MN*2],rs[MN*2],id[MN*2],len,n,totnode,rev[MN*2];
int build(int l,int r){
  if(r<len-n)return -1;
  if(l==r)return id[l];
  int mid=(l+r)>>1,ret=++totnode;
  ls[ret]=build(l,mid),rs[ret]=build(mid+1,r);
  return -ret;
}
void create_circuit(int M, vector<int> A) {
  A.push_back(0);
  len=1;
  n=A.size();
  while(len<n)len<<=1;
  for(int i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
  static int tmp[MN*2];
  for(int i=len-n;i<len-1;++i)tmp[i-(len-n)]=i;
  sort(tmp,tmp+n-1,[](const int &x,const int &y){return rev[x]<rev[y];});
  for(int i=0;i<len;++i)id[i]=-1;
  for(int i=0;i<n-1;++i)id[tmp[i]]=A[i];
  id[len-1]=0;
  build(0,len-1);
  answer(vector<int>(M+1,-1),vector<int>(ls+1,ls+totnode+1), vector<int>(rs+1,rs+totnode+1));
}

标签:IOI2018,rs,int,MN,len,开关,二叉树,UOJ,408
来源: https://www.cnblogs.com/YouthRhythms/p/16413267.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有