[HNOI2015]部分题解

 

Day1

 

  T2 [HNOI2015]接水果

 

  风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? 

 

 

  

  代码能力太弱了> < 写了好久啊这道题..

  首先分析题目,“盘子能接住水果当且仅当盘子的路径是水果的子路径”

  这显然不符合常识啊QAQ 不过似乎也有那么一点提示的意思...

  

  首先我们来考虑一种普遍的情况:

  当盘子长成这个样子的时候,水果的路径想要包含它,那么两个端点一定在图中所画的区域内

  即一个端点在u的子树中,一个端点在v的子树中

  一棵子树内的dfs序都是连续的,我们可以求出每个端点及其子树中dfs序的最大值和最小值

  下面都直接写成fir[x]和las[x]

  那么水果的两个端点分别在[fir[u],las[u]],[fir[v],las[v]]之中

  

  再考虑特殊情况,即盘子为链状

  

  首先显然水果的一个端点必然在v的子树中

  另一个端点只要不在w及w的子树中即可

  可以看出这些节点的dfs序正好被w的子树这一段连续的值分成两段

  也就是[1..fir[w]-1]和[las[w]+1..n]

 

  考虑解决下面一个子问题:

    给定一些盘子和一些水果,计算出每个水果能被多少个盘子接住

  根据上面我们的结论,可以把每个盘子能接住水果的两段区间分别看成x坐标的区间和y坐标的区间

  每个水果的两个端点看成每个水果的x坐标和y坐标

  然后问题就转变成了每个水果点能被多少个盘子矩形包含

  可以用树状数组+扫描线解决

 

  接下来要把原问题转化到子问题上

  我们先把所有的盘子按照权值排序 然后考虑二分

  如果能覆盖一个水果的1~mid的所有盘子数>=该水果询问的k值

  说明答案在[1,mid]当中,否则在[mid+1,r]中

  但是为了减少计算量 我们可以每次只计算L~mid中的盘子

  需要改变的就是划分到[mid+1,r]时减去[L,mid]中累积的答案

 

  

 


 

 

  T3[HNOI2015]菜肴制作

  知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。 ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为1。由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M 条形如“i 号菜肴‘必须’先于 j 号菜肴制作”的限制,我们将这样的限制简写为<i,j>。现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小 A能尽量先吃到质量高的菜肴:也就是说,(1)在满足所有限制的前提下,1 号菜肴“尽量”优先制作;(2)在满足所有限制,1号菜肴“尽量”优先制作的前提下,2号菜肴“尽量”优先制作;(3)在满足所有限制,1号和2号菜肴“尽量”优先的前提下,3号菜肴“尽量”优先制作;(4)在满足所有限制,1 号和 2 号和 3 号菜肴“尽量”优先的前提下,4 号菜肴“尽量”优先制作;(5)以此类推。 例1:共4 道菜肴,两条限制<3,1>、<4,1>,那么制作顺序是 3,4,1,2。例2:共5道菜肴,两条限制<5,2>、 <4,3>,那么制作顺序是 1,5,2,4,3。例1里,首先考虑 1,因为有限制<3,1>和<4,1>,所以只有制作完 3 和 4 后才能制作 1,而根据(3),3 号又应“尽量”比 4 号优先,所以当前可确定前三道菜的制作顺序是 3,4,1;接下来考虑2,确定最终的制作顺序是 3,4,1,2。例 2里,首先制作 1是不违背限制的;接下来考虑 2 时有<5,2>的限制,所以接下来先制作 5 再制作 2;接下来考虑 3 时有<4,3>的限制,所以接下来先制作 4再制作 3,从而最终的顺序是 1,5,2,4,3。 现在你需要求出这个最优的菜肴制作顺序。无解输出“Impossible!” (不含引号,首字母大写,其余字母小写) 

 
  虽然看到题解的时候觉得不难但是真的感觉是一道很有趣的题^_^
  我的想法是按序号依次定下每一个点,必在其前面的点+1就是该点的位置
  “必在其前面的点”由两个部分组成
  1)由限制带来,必在其之前做的菜
  2)可以在该点前面出现且编号必该点小的点及其1)2)部分点
  刚开始考虑了一个分治做法 但到最后并没有实现 而且就算实现了效率也很低
  然而我们倒过来看,每个点被限制的点被强制推到其后面(这个后面是倒过来看的后面
  编号比该点小的点,或许可以在前面取出但是在取舍的过程中将编号较大的该店取出
  反着来看就是一个拓扑排序+堆的实现
  边反着造,堆用大根堆,所有的思路都是逆着的
  很有趣。
 

  

Day2


  T1[HNOI2015]落忆枫音 

  不妨假设枫叶上有 n个穴位,穴位的编号为 1 ~  n。有若干条有向的脉络连接着这些穴位。穴位和脉络组成一个有向无环图——称之为脉络图(例如图 1),穴位的编号使得穴位 1 没有从其他穴位连向它的脉络,即穴位 1 只有连出去的脉络;

  由上面的故事可知,这个有向无环图存在一个树形子图,它是以穴位 1为根的包含全部n个穴位的一棵树——称之为脉络树(例如图 2和图 3给出的树都是图1给出的脉络图的子图);值得注意的是,脉络图中的脉络树方案可能有多种可能性,例如图2和图 3就是图 1给出的脉络图的两个脉络树方案。  

        
  脉络树的形式化定义为:以穴位 r 为根的脉络树由枫叶上全部 n个穴位以及 n-  1 条脉络组成,脉络树里没有环,亦不存在从一个穴位连向自身的脉络,且对于枫叶上的每个穴位 s,都存在一条唯一的包含于脉络树内的脉络路径,使得从穴位r 出发沿着这条路径可以到达穴位 s。  
  现在向脉络图添加一条与已有脉络不同的脉络(注意:连接 2个穴位但方向不同的脉络是不同的脉络,例如从穴位3到4的脉络与从4到3的脉络是不同的脉络,因此,图 1 中不能添加从 3 到 4 的脉络,但可添加从 4 到 3 的脉络),这条新脉络可以是从一个穴位连向自身的(例如,图 1 中可添加从 4 到 4 的脉络)。原脉络图添加这条新脉络后得到的新脉络图可能会出现脉络构成的环。  
  请你求出添加了这一条脉络之后的新脉络图的以穴位 1 为根的脉络树方案数。 
  由于方案可能有太多太多,请输出方案数对 1,000,000,007 取模得到的结果。
 
  考场上花了一定时间脑补出了:有向无环图的生成树个数等于非根节点的入度积
  然后后来得知这个图叫做DAG,然后这好像是一个定理...
  然后考虑加一条边,按照刚刚入度积来计算显然是不对了
  我们多计算了一些并不成立的情况
  即:最后生成的图包含了一个环的情况
  为何会包含一个环?显然是包含了新加入的(s,t)边
  (s,t)边与原图中t到s的路径共同构成了一个环
  我们设所有节点入度积为S
  我们要求的答案
  = S - 不满足题意的情况
  = S - 出现环的情况
  = S - 存在t到s的路径的情况
  然后我们来考虑存在t到s的路径的情况,我们先定下一条t到s的路径
  对于不在路径中的点,我们仍然可以有其入度种取法
  那么对于这条路径存在的次数 = 非路径节点的入度积 = S/路径中节点的入度积
  怎样高效地统计出所有t到s的路径对答案的贡献呢?
  我们考虑DP
  我们需要得到的是每条路径上节点的1/入度积的乘积,最后再乘S
  我们设t-a的入度积为A,t-b的入度积为B  
  则t-a-c的路径上入度积为A*b[c],t-b-c的路径上入度积为B*b[c]
  总共到c点的路径入度积为b[c]*(A+B)
  我们设f[i]为t-i路径上所有入度积的倒数和
  累积所有父亲的答案和,最后乘上1/b[i]即可
  然后最后输出S-f[s]*S
  这里的运算是在模大质数下进行的,所以除法运算可以用乘法逆元来代替
  另外DP的顺序我的做法是重新DFS入度,然后按照拓扑序列进行
  最后注意两个细节:
  1)当添加的边s = t,即添加的是自环的时候,直接输出S
  2)当添加的边t = 1,也直接输出S
 
 

  
 
 
 T3[HNOI2015]实验比较

  小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验。实验用到的图片集一共有 N 张图片,编号为 1 到 N。实验分若干轮进行,在每轮实验中,小 D会被要求观看某两张随机选取的图片, 然后小D 需要根据他自己主观上的判断确定这两张图片谁好谁坏,或者这两张图片质量差不多。 用符号“<”、“>”和“=”表示图片 x和y(x、y为图片编号)之间的比较:如果上下文中 x 和 y 是图片编号,则 x<y 表示图片 x“质量优于”y,x>y 表示图片 x“质量差于”y,x=y表示图片 x和 y“质量相同”;也就是说,这种上下文中,“<”、“>”、“=”分别是质量优于、质量差于、质量相同的意思;在其他上下文中,这三个符号分别是小于、大于、等于的含义。图片质量比较的推理规则(在 x和y是图片编号的上下文中):(1)x < y等价于 y > x。(2)若 x < y 且y = z,则x < z。(3)若x < y且 x = z,则 z < y。(4)x=y等价于 y=x。(5)若x=y且 y=z,则x=z。 实验中,小 D 需要对一些图片对(x, y),给出 x < y 或 x = y 或 x > y 的主观判断。小D 在做完实验后, 忽然对这个基于局部比较的实验的一些全局性质产生了兴趣。在主观实验数据给定的情形下,定义这 N 张图片的一个合法质量序列为形如“x1 R1 x2 R2 x3 R3 …xN-1 RN-1 xN”的串,也可看作是集合{ xi Ri xi+1|1<=i<=N-1},其中xi为图片编号,x1,x2,…,xN两两互不相同(即不存在重复编号),Ri为<或=,“合法”是指这个图片质量序列与任何一对主观实验给出的判断不冲突。例如: 质量序列3 < 1 = 2 与主观判断“3 > 1,3 = 2冲突(因为质量序列中 3<1 且1=2,从而3<2,这与主观判断中的 3=2 冲突;同时质量序列中的3<1 与主观判断中的 3>1 冲突) ,但与主观判断“2 = 1,3 < 2  不冲突;因此给定主观判断“3>1,3=2时,1<3=2 和1<2=3 都是合法的质量序列,3<1=2 和1<2<3都是非法的质量序列。由于实验已经做完一段时间了,小D 已经忘了一部分主观实验的数据。对每张图片 i,小 D 都最多只记住了某一张质量不比 i 差的另一张图片 Ki。这些小 D 仍然记得的质量判断一共有 M 条(0 <= M <= N),其中第i 条涉及的图片对为(KXi, Xi),判断要么是KXi   < Xi  ,要么是KXi = Xi,而且所有的Xi互不相同。小D 打算就以这M 条自己还记得的质量判断作为他的所有主观数据。现在,基于这些主观数据,我们希望你帮小 D 求出这 N 张图片一共有多少个不同的合法质量序列。我们规定:如果质量序列中出现“x = y”,那么序列中交换 x和y的位置后仍是同一个序列。因此: 1<2=3=4<5 和1<4=2=3<5 是同一个序列, 1 < 2 = 3 和 1 < 3 = 2 是同一个序列,而1 < 2 < 3 与1 < 2 = 3是不同的序列,1<2<3和2<1<3 是不同的序列。由于合法的图片质量序列可能很多, 所以你需要输出答案对10^9 + 7 取模的结果
  这道题做出来真的很有成就感..花了三个半小时做..
  不仅是感觉推出来的是自己以前很怕的东西..而且这种怒刷存在感的感觉也很棒..!
 
  第一感觉是拓扑序列计数?发现网上的做法最好也是n<=20的,显然题目隐藏了一些条件
 
  首先分析题目隐含内容,有几个加粗的字:每个x1只会出现一次
  那么也就是说每个点只有一个父亲,也就是原图是一棵树
  (当然现在说这句话只是初步的结论,一会儿再考虑反例)
 
  对于两棵不同的数,各自的序列排好序之后合并即可
  对于一个节点的不同子树也是这样
  
  接着考虑如何合并的问题 
  如果不考虑等号那就非常简单的排列组合
 
  然后看到原题中的“1 = 2 = 3与2 = 1 = 3”相等算是相同的情况
  于是就想到把相等的缩成一个点
  想了一下显然可以
 
  这样的话两个序列合并还需要枚举一个量:合并后的长度
 
  设以i为root的子树构成长度为k的序列方案数为f[i,k]
  以j为root的子树构成长度为t的序列方案数为f[j,t]
  设合并后的长度为p
  以序列i为基础,我们把j插进去,那么增加的长度 = (p-i)这个显然
  也就是j序列中插入i间隙的点数
  缩的点 = j-(p-i)
  然后把这两种情况分开计算
  用来缩点的方案 = C(j,j-(p-i))
  插入间隙的方案要复杂一些,我们设把j序列割成q份
  方案 = sigma(c(i+1,q)*c(j-1,q))
  这个我们可以n^3预处理出来
  最后的复杂度是n^4的,八中上的极限数据我跑出来大约0.4s
 
  再说一些零碎的东西
  1)读进来的 = 号我们可以直接把两个点合并,用并查集实现
    一会儿加边的时候要注意用getfa后的点
  2)我们添加一个root,连接每棵树的树根,树根的特点是b[i] = 0
    然而只考虑这一个条件是不够的,注意这个点一定是存在的点,即getfa(i) = i
  3)回归到上面打下的铺垫,实际上,每个点的入度都为1还存在一种情况
    即所有的点均分布在环中(环的个数可能不止一个)
    这种情况显然是不可能满足的,于是特判输出0
  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  

posted @ 2015-04-22 16:12  mjy0724  阅读(1545)  评论(0编辑  收藏  举报