NFLSPC #1 B题 Permutation 题解

2018-12-02 17:09:56 By diamond_duke

我们按照 $\lvert a[x]-a[y]\rvert$ 从小到大的顺序考虑每一对 $(x,y)$,每次考虑把 $[a_x,a_y]$ 的数字重新排列,使得 $a_x$ 和 $a_y$ 被交换了,而之前所有已知条件都满足。得到这个构造之后直接询问一下这个新的排列是否可行,就可以得到有没有 $(x,y)$ 这个限制。

首先自然的想法是直接拓扑排序一下,如果有环那么一定有限制。但是这样因为单次拓扑排序时间复杂度是 $\Theta (n^2)$ 的,所以总复杂度是 $\Theta (n^4)$ 的。显然 $TLE$(我特意卡了这个做法)。

事实上,这个东西可以如下构造:

  • 首先,如果同时存在一个 $(x,i)$ 和 $(i,y)$ 的限制,那么 $(x,y)$ 一定有限制,不用询问。
  • 否则,一定不存在一个 $i$,使得 $a_x\le a_i\le a_y$,且同时 $(x,i)$ 和 $(i,y)$ 都有限制。设 $A$ 为 $\{i\mid (x,i)\in E,a_x\le a_i\le a_y\}$,其中 $E$ 为已知的限制集合。设 $B$ 为剩下的满足 $a_x\le a_i\le a_y$ 的 $i$。则考虑如下构造 $a'$:
    • 把 $B$ 中的位置按照 $a_i$ 从小到大的顺序设为 $[a_x,a_x+\lvert B\rvert)$;
    • $a'_y$ 设为 $a_x+\lvert B\rvert$;
    • $a'_x$ 设为 $a_x-\lvert A\rvert$;
    • 再把 $A$ 中的位置按照 $a_i$ 从小到大的顺序设为 $(a_y-\lvert A\rvert,a_y]$ 即可。

容易验证这样符合我们上面的要求。

于是我们最后可以得出所有约束条件。然后类似 "HNOI 2015 菜肴制作" 那样贪心拓扑排序即可得到字典序最小的排列了。

时间复杂度:$\Theta (n^3)$,询问次数:至多 $n\times (n-1)/2$。

参考代码:

2018-6-9 题解

2018-06-09 11:28:35 By diamond_duke

骑士游戏

考虑 $dp$,类似 $SPFA$ 那样做:每次取出队头元素,看看有没有被更新,如果 $dp$ 被更新了就把他的前驱入队,然后重复上述过程。

时间复杂度:$\Theta (SPFA_{n,\sum R})$。

奇怪的计算器

询问离线,用线段树维护每个询问的答案。注意到这些操作过程中,数字的相对顺序不会改变(原来的顺序就是新的顺序)。那么我们把询问排序,用线段树维护。每次溢出的区间一定是一个前缀或者后缀,树上二分求出这个区间即可。

于是这个线段树只要支持:

  • 区间加
  • 区间乘
  • 区间赋值
  • 区间加上一条直线($@$操作)
  • 树上二分出:第一个大于/小于某个数的位置,以及$@$后第一个溢出的位置
  • 单点查询

维护一群懒标记即可,时间复杂度:$\Theta (n\log_2n)$。

小园丁与老司机

先考虑前两问,考虑 $dp$,转移时枚举下一行进入了哪个点以及从哪里进入,然后计算出当前行最多能走多少,转移即可。构造路径的话直接推即可。

在考虑第三问:根据之前的 $dp$ 值进行一遍 $dfs$,即可知道哪些边可能经过。这些边都要被覆盖,所以是一个下界最小流问题。因此跑网络流即可(一定满流,可以省一次)。

时间复杂度:$\Theta (n\times \max_Y\{\sum_{i=1}^n[y_i=Y]\}+最大流_{n,O(n)})$。

NFLSOJ支持自动识别(Subtask的)数据了!

2018-06-02 20:57:31 By diamond_duke

现在NFLSOJ可以方便的进行捆绑测试以及识别数据了!

只要将数据分别放入每个文件夹(文件夹命名需为subtaskx的形式,其中x为子任务编号)中,即可实现捆绑测试。同时为了与旧版兼容,这种格式需要在problem.conf中添加一句:subtask_in_folder on

同时,新加入了功能:自动识别数据配对关系。具体来说,如果是采用了subtask_in_folder格式的话(否则暂不支持,尽请谅解),我们会对于文件夹中每一个形如xxx.{$input_suf}的文件来寻找对应的xxx.{$output_suf},并智能排序。例如,如果input_sufinoutput_sufout,而文件夹内部有如下文件:

  • rand1.in
  • rand2.in
  • ……
  • rand10.in
  • rand1.out
  • rand2.out
  • ……
  • rand10.out
  • gen1.in
  • gen2.in
  • ……
  • gen10.in
  • gen1.out
  • gen2.out
  • ……
  • gen10.out

那么最终配对结果为:gen1.in/outgen2.in/out,……,gen10.in/outrand1.in/outrand2.in/out,……,rand10.in/out(对于只有数字不同的而其余部分均相同的测试点,会按照数字大小进行排序,否则会按照字典序进行排序)。

同时,n_testssubtask_end_xinput_pre以及output_pre不用填写n_testssubtask_end_x即便填写了也没有任何用处,而input_preoutput_pre用于表示在评测机中的文件名,用处不大,建议省略)。

而其他的诸如time_limitsubtask_dependence_xn_ex_tests以及n_sample_tests等等与原来一样,没有任何区别。

祝大家出题愉快!

通过数据中的子文件夹实现捆绑测试的方法

2018-05-30 12:04:49 By diamond_duke

现在NFLSOJ可以方便的支持捆绑测试了!

只要将数据分别放入每个文件夹(文件夹命名需为subtaskx的形式,其中x为子任务编号)中,即可实现捆绑测试。注意subtask_end_x仍要填写,用于表示每个子任务的测试点个数。同时为了与旧版兼容,这种格式需要在problem.conf中添加一句:subtask_in_folder on

同时,n_testsn_ex_tests以及n_sample_tests不用填写n_tests即便填写了也没有任何用处,另外两个可以正常使用)。

而其他的诸如input_pretime_limitsubtask_dependence_x等等与原来一样,没有任何区别。

祝大家出题愉快!

2018-3-29 题解

2018-03-29 11:25:20 By diamond_duke

前言

出题人个人认为的题目难度排序是(难度从小到大):第二题,第三题,第一题。为了防止部分选手卡题,所以特意添加了提示,是不是很良心?(雾)

小D与迷宫(maze)

问题转化

可以发现,题目等价于求,有多少个$n$个点(带标号)的深度不超过$k$(根节点深度为$1$)的森林。

Algorithm 1

当$k=1$时,那么显然所有点都得要是汇点,也就是没有边。因此此时答案为$1$。

时间复杂度:$\Theta (T)$,空间复杂度:$\Theta (1)$,期望得分:$5$分。

Algorithm 2

当$k=2$时,我们可以枚举汇点个数,那么其他点可以随意的挂在这些点上面。即,答案为:$\sum_{i=1}^n(n-i)^i\cdot {n\choose i}$。

时间复杂度:$\Theta (T\cdot n\log_2n)$,空间复杂度:$\Theta (1)$,期望得分:$10$分,结合Algorithm 1可以得到$15$分。

Algorithm 3

Algorithm 2的基础上进行优化,我们可以改为枚举深度为$2$的点,那么答案为$\sum_{i=0}^{n-1}i^{n-i}\cdot {n\choose i}$,我们预处理阶乘、阶乘的逆元以及逆元即可做到$\Theta (n)$计算。

时间复杂度:$\Theta (T\cdot n)$,空间复杂度:$\Theta (n)$,期望得分:$25$分,结合Algorithm 1可以得到$30$分。

Algorithm 4

当$k=n$时,我们就是要求迷宫的个数。那么可以由$Matrix\ Tree$定理算出答案即为:$(n+1)^{n-1}$。

时间复杂度:$\Theta (T\cdot \log_2n)$,空间复杂度:$\Theta (1)$,期望得分:$20$分,结合Algorithm 1 & 3可以得到$50$分。


看起来有特殊性质的点都基本上用完了,我们来想一想通用的解法。

Algorithm 5

Algorithm 4可知,迷宫个数不超过$(n+1)^{n-1}$,那么暴力枚举每一个迷宫并进行判断的复杂度为$\Theta ((n+1)^{n-1}\cdot n)$。

时间复杂度:$\Theta (T\cdot (n+1)^{n-1}\cdot n)$,空间复杂度:$\Theta (n)$或$\Theta ((n+1)^{n-1})$,期望得分:$10$分,结合Algorithm 1 & 3 & 4可以得到$60$分。

Algorithm 6

考虑$dp$,设$f_{k,n}$表示深度$\le k$的$n$个点带标号森林的个数。

设$g_{k,n}$表示深度$\le k$的$n$个点带标号树的个数。

那么我们考虑把一个树去掉根节点,他就变成了一个深度$-1$的森林,因此:$g_{k,n}=f_{k-1,n-1}\cdot n$。而森林是由一群树组成的,那么这里也是利用组合数加以转移的。

时间复杂度:$\Theta (n^2\cdot k+T)$,空间复杂度:$\Theta (n^2\cdot k)$,期望得分:$40$分,结合Algorithm 1 & 3 & 4可以得到$80$分。

Algorithm 7

考虑指数型生成函数。设$\hat F_k=\sum_{i=0}^{+\infty}f_{k,i}\cdot \dfrac{x^i}{i!},\hat G_k=\sum_{i=0}^{+\infty}g_{k,i}\cdot \dfrac{x^i}{i!}$。

那么有:$\hat G_k=\hat F'_{k-1}$,其中$\hat F'_k=\sum_{i=1}^{+\infty}f_{k,i-1}\cdot \dfrac{x^i}{i!}$。

因为森林可以表示成树的无序不交并,所以由泰勒展开式可知$\hat F_k=e^{\hat G_k}=e^{\hat F'_{k-1}}$,写一个多项式$exp$就好了。

时间复杂度:$\Theta (n\cdot k\cdot \log_2k)$,空间复杂度:$\Theta (n\cdot k)$,期望得分$75$分或$80$分(取决于常数),结合Algorithm 4可以得到$95$或$100$分。

小D与道路(road)

Algorithm 1

信仰法:直接输出所有边权和,可以通过第一个子任务。

时间复杂度:$\Theta (m)$,空间复杂度:$\Theta (1)$,期望得分:$5$分。

Algorithm 2

暴力枚举每一条边是否保留,然后通过$dfs$或者$bfs$判断是否美观。

时间复杂度:$\Theta (2^m\cdot n)$,空间复杂度:$\Theta (n+m)$,期望得分:$30$分,结合Algorithm 1可以得到$35$分。

问题转化

考虑$1\sim n$的路径上的点,称他们为关键点,则美观的图的形态一定是:关键点下面挂着一个子图(可以为空,也可以不联通),而且不同点下面的子图互不连通

Algorithm 3

那么考虑$dp$:$dp_{S,u}$表示现在考虑点集$S$,他们之间的连边已经确定了,且$1\sim u$的路径唯一。

于是转移有两种:

  • 新增一个关键点,设这个点是$v$,则$v\not \in S$。
    因为他得要接在$u$后面,所以$(u,v)\in E$。
    那么转移就是$dp_{S\cup \{v\},v}\gets dp_{S,u}+w(u,v)$,其中$w(u,v)$表示$u,v$之间的边的边权;
  • 给$u$下面挂上一个子图,设这个子图的点集为$T$,则$S\cap T=\phi$。
    那么我们可以保留$T\cup \{u\}$中的所有边,而其他边一条不能有,否则就违反上面加粗的条件了。
    则转移就是$dp_{S\cup T,u}\gets dp_{S,u}+sum_{T\cup \{u\}}$,其中$sum_S$表示点集$S$内部的边权和。

那么转移的复杂度就是$\Theta (n+2^n)$,而状态数为$\Theta (2^n\cdot n)$,因此总时间复杂度为$\Theta (4^n\cdot n)$,空间复杂度为$\Theta (2^n\cdot n)$,期望得分:$50$或$68$分(取决于算法实现中的常数),结合Algorithm 1可以得到$55$或$73$分。

Algorithm 4

注意到Algorithm 3的时间瓶颈在于第二种转移,考虑优化。

因为$S\cap T=\phi$,因此$T\subset \overline S$,那么我们可以直接枚举$\overline S$的子集,设这个集合为$X$,那么可以用下面的伪代码段实现(这里的$X,T$均用二进制来状态压缩):

$T\ \gets\ X$
while $T\ \ne\ \phi$


// do something here


$T\ \gets\ (T-1)\wedge X$
end while

那么利用等比数列求和公式,可以证明这样优化之后算法的总复杂度是$\Theta (3^n\cdot n)$,空间复杂度仍然是$\Theta (2^n\cdot n)$,期望得分:$83$或$90$分(取决于常数因子),结合Algorithm 1可以得到$88$或$95$分。

Algorithm 5

诶?我怎么写了Algorithm 4然后加了点(wáng)优(yì)化(sōng)就$100$了?是不是数据造水了?

别急,我们来理性分析一波:显然只有$1\in S$的状态才是有效的,所以我们在进行转移之前直接跳过无用状态就可以使状态数变成至多$2^{n-1}\cdot n$,那么这样之后总的复杂度也就是$O(3^{n-1}\cdot n)$。

所以理论上加入跳过无用状态这么一个一行代码的优化就可以获得$100$分辣!是不是很简单?

小D与圣诞树(tree)

因为对于$100\%$的数据,$n,m$同阶。所以题解中的复杂度均用$n$代替$m$。

定义题解中用到的一些符号如下:

  • $f_u$表示点对$(1,u)$的美观度。
  • $p_{u,v}$表示距离$v$最近的$u$的邻居,特别地,$p_{u,u}=u$。

Algorithm 1

暴力按照题意模拟。

时间复杂度:$\Theta (n^2)$,空间复杂度:$\Theta (n)$,期望得分:$15$分。

Algorithm 2

对于$t=1$的子任务,因为没有修改,那么因为每个点的初始装饰品均不相同,所以点对$(u,v)$的美观度就是两点路径上经过的点数。那么对于点对的询问,直接求出$LCA$然后算距离即可。对于子树的询问,可以预处理每一个子树中最深的点的深度。

时间复杂度:$\Theta (n\log_2n)$或$\Theta (n)$,空间复杂度:$\Theta (n\log_2n)$或$\Theta (n)$,期望得分:$10$分,结合Algorithm 1可以得到$25$分。

Algorithm 3

对于$t=2$的子任务,因为是一条链,由定义可以知道显然越深的点的$f$越大。所以对于子树询问,肯定是选择最深的点,因此只要维护现在有多少种不同的颜色即可。

对于点对询问,我们可以注意到最终的颜色一定分成一段一段的,同一种颜色不会被断开。那么我们设询问的$(u,v)$中,深度较深的为$v$,则答案就是$f_v-f_u+1$,这可以用线段树维护$f$来实现。

时间复杂度:$\Theta (n\log_2n)$,空间复杂度:$\Theta (n)$,期望得分:$15$分,结合Algorithm 1 & 2可以得到$40$分。

问题转化

有了链的问题的铺垫,我们可以发现在树上每种颜色也是一条竖着的路径(即上面的点的深度是单调的,不会拐弯)。

因此我们设$LCA(u,v)=x$,则$x$的颜色不会和$p_{x,u},p_{x,v}$均相等。那么我们讨论一下有没有和其中某一个相等,就可以得到点对$(u,v)$的美观度公式为:$f_u+f_v-2\cdot f_x+1$。

Algorithm 4

对于$t=3,4,5$的子任务,因为数据随机,所以树的期望深度是$\log_2n$级别的。那么我们可以使用线段树维护$f$,每次修改时暴力的走$u$到$1$的路径,算出每一个子树的$f$的变化,用线段树区间修改。

询问点对时求出$LCA$,然后利用上面的式子求。子树的询问可以维护线段树区间最大值来实现。

时间复杂度:$\Theta (n\log_2^2n)$,空间复杂度:$\Theta (n\log_2n)$,期望得分:$28$分(如果其中某种询问的处理方法没有想到也可以获得$10$分),结合Algorithm 1 & 2 & 3可以得到$68$分。

Algorithm 5

联想到$ZJOI\ 2018\ 历史$,可以发现这两个题目的修改方式很类似。

注意到我们如果把同色点(颜色均指装饰品的种类)之间的边看成实边,异色点之间的边看成虚边,那么其实一次对$u$的修改就是$LCT$中$access(u)$的操作。

于是我们可以直接用一棵$LCT$,在$access$中连接、断开边会导致各自的子树$\pm 1$,那么直接用线段树区间加维护$f$即可。询问的处理方法同Algorithm 4

时间复杂度:$\Theta (n\log_2^2n)$,空间复杂度:$\Theta (n\log_2n)$,期望得分:$95$或$100$分(取决于算法实现时的常数)。

diamond_duke Avatar