2020.07.22【省选B组】模拟(李超树)

T1:这题比较简单。

首先把所有串翻转,然后问题就变成了求公共前缀。接着可以建出trie,容易发现一个表示字符串的节点只能走到表示字符串的父亲、儿子和兄弟节点。这样就可以设f[x]表示从x下方走到x的最长路径。f[x]就等于x的儿子的最长路径加上x的儿子中能表示字符串的节点的个数。求答案时枚举x然后在儿子中选两条最长的链再加上儿子中能表示字符串的节点的个数就好了。

 

T2:李超树模板题。

因为询问的x0在1~100000中,所以我们只需要对这些点建线段树。线段树的每一个节点只能存放一条线段。

对于每次加入一条线段,我们可以先找到这条线段覆盖的log个区间,然后再在这log个区间上操作。每次操作分三种情况:

1、若当前区间没有线段,则直接把要加入的线段加入这个区间

2、若当前区间的线段与加入的线段的交点不在这个区间内,则比较一下那一条线段更优,留下最右的一条

3、若交点在当前区间内,则看一看那一条线段较优的部分更长,留下较优部分更长的线段,然后把另一条线段递归下去处理。容易发现另一条线段只需递归左右区间中的一个即可。

对于每次查询,我们之间查找x0对应的log个区间,带入x0然后选出最大值。

 

T3:首先发现当k*k>n时A必胜,所以k<20(我不太会证)。

然后还有一个性质:第i次会在深度为i的点上画叉。因为第i次在小于i的深度上画叉是没意义的,而在大于i的深度上画叉又不如在深度为i的点上画叉优。

接着我们可以先重构树(把没有用的节点删去),然后求出dfs序。容易发现每一个节点都有两个属性(深度、画叉时再dfs序上覆盖的区间[l,r])。现在我们的问题就成了要选出若干个区间,要求深度不重复且能覆盖所有叶子节点的dfs序位置。

因为k<20,所以可以状压dp。设f[i][s]表示前i个区间所用深度集合为s是否能把1~r[i]中的叶子位置覆盖完。转移时枚举下一个使用的区间,注意深度不重且中间不能漏掉叶子没有覆盖。在这种转移方式下我们需要事先将l从小到大排序。

不过这样会超时,我们要优化一下。顺带说一下f用bool类型存可以节省空间。有一个优化就是我们压缩区间,只存每一个原来dfs序的区间能覆盖的叶子的区间,这样可以节省时间。然后在转移的时候我们枚举状态,接着用前面的状态转移过来。在设状态的时候把状态改成f[i][s]表示用s集合的深度是否能覆盖1~i的区间(即将i的f值存在r[i]上),这时要先将r从小到大排序,在转移时用过break等优化就可以通过这题了。

你可能感兴趣的:(【NOIP提高组】模拟A组)