T1
####算法一
暴力枚举所有可能的$a_2$并递推判断。复杂度$O(r \times k)$,预期得分10分。
####算法二
$a_k$可以表示为$a_1$与$a_2$的线性组合。使用递推计算出系数,并暴力枚举所有可能的$a_2$判断。复杂度$O(r+k)$,预期得分30分。
####算法三
暴力枚举所有可能的$a_2$并使用矩阵乘法判断。复杂度$O(r \times \log(k))$,预期得分50分。
####算法四
与算法二类似,使用递推计算出系数,此时可以发现可能的$a_2$满足一个同余方程,使用扩展欧几里得或逆元求解即可。可以通过测试点6,7。
####算法五
将算法四中计算系数的方式改为矩阵乘法,可以通过测试点8。
####算法六
由于$p$可能不是质数,所以需要判断不互质的情况,然后使用扩展欧几里得或欧拉定理求解同余方程。可以通过所有数据。
T2
## 算法一(针对测试点1)
我们可以暴力地维护锅所有锅内的食物,并暴力查询即可。
时间复杂度:$O\left( \left( n+Q\right)Q\right)$或$O\left( \left( n+Q\right)Q\log{n}\right)$
期望得分:8分
## 一些想法
我们可以分别维护锅内(未熟)的食物和锅外(已熟)的食物。对于操作$1,3$和操作$2$的第一部分(判定是否有已熟的食物),我们可以在锅外查询;对于操作$2$的第二部分(求最近的熟食),我们可以在锅内查询。
## 算法二(针对测试点1-3)
对于锅内的每种食物,我们分别使用链表(或vector)维护,这样操作$2$查询和操作$0$插入的操作**总**复杂度是$O\left( Q\right)$。
对于锅内食物熟了的时间,我们发现对于每种食物,食物煮熟的顺序和食物被放入的顺序是相同的,于是我们每次事件前暴力维护每个链表即可。总复杂度为$O\left( nQ\right)$。
对于锅外的食物,我们用数组(即$n$个变量)维护。于是对于每种操作$2$的第二部分查询,我们可以用$O\left( 1\right)$的时间回答;对于操作$1,3$的查询,我们可以用$O\left( n\right)$的时间回答。
于是我们即可在$O\left( nQ\right)$的时间复杂度内完成此题。
期望得分:20分
## 算法三(针对测试点4-5)
我们发现每个食物的$s$值均为$1$,也就是说在其被放入锅内后一个时刻即会被煮熟。而题目保证每一时刻最多只有一个事件,因此我们可以认为锅内没有食物。
于是我们只需要用树状数组维护锅外的食物,并支持树状数组上二分,即可轻松解决此题。(当然,我们也可以借助set,不过这可能会使你的程序有更大的常数)
时间复杂度:$O\left( Q\log{n}\right)$
期望得分:16分
## 算法四(针对测试点4-7)
对于锅内,我们可以使用链表(或vector)维护;对于锅外,我们可以用树状数组维护。
由于所有食物$s$值相同,所以所有食物被煮熟的顺序与它们被放入锅内的顺序一致,我们可以用指针维护下一个将要被煮熟的食物的位置,即可快速完成“从锅内到锅外”的操作。
时间复杂度:$O\left( Qlog{n}\right)$
期望得分:38分
## 算法五(针对测试点8-9)
我们发现不存在区间求和操作,于是我们同样适用链表(或vector)维护锅内,用multiset或map维护锅外即可。(这两个数据结构完美支持所有查询、修改操作)
对于食物被煮熟的顺序,我们可以额外使用一个priority_queue或堆来维护锅内的食物,其中关键字为食物被煮熟的时间。每次操作前,我们不断弹出堆顶,直到堆顶还未被煮熟为止,并将被弹出的食物加入锅外即可。
我们也可以将所有操作$t 0 id$拆分成$2$个操作:
1. $t$时刻将食物$id$加入锅内。
2. $t+s[id]$时刻将食物$id$从锅内取出,并加入锅外。
并将所有操作重新按时间顺序排序,然后依次执行。
时间复杂度:$O\left( Qlog{n+Q}\right)$
期望得分:14分
## 算法六(针对所有测试点)
结合算法五和支持二分功能的树状数组即是这道题目的标算。
时间复杂度:$O\left( Qlog{n+Q}\right)$
期望得分:100分
## 针对程序常数的说明
对于使用支持二分功能的树状数组、priority_queue以及multiset或map的程序,在实际运行速度上有着一些不同。这是因为前两个数据结构的常数远小于后二者。对于使用其他数据结构的程序,有可能同样会有不同程度的常数问题,选手也因此会得到$96-100$的分数(即有可能无法通过最后两个测试点)。
在实际测试中,上面提到的四种数据结构都可以获得$100$分。
T3
## 短短的题目 给定 $n$ 行 $m$ 列的网格,每个格子中有上下左右四个方向之一的箭头或“`.`”符号(整个网格中共有 $k$ 个)。在每个标有“`.`”的格子中填入一个箭头,使得从任何一个格子出发沿着箭头所指的方向行走,都不会进入循环,求填入的方案数。 ## 长长的题解 ### 一
测试点编号 |
$n$, $m$ |
$k$ |
特殊约定 |
1 |
$\leq 50$ |
$= 0$ |
无 |
2 |
$\leq 200$ |
我是来自 Div. 2 的小可爱,已经 AK 啦,所以来看看题,不过好难的样子…… 嗯? 对于 $k = 0$ 的情况,直接按题意进行检查可以通过第 1 个测试点,时间复杂度 $O(n^2 m^2)$;加入记忆化可以通过第 2 个,时间复杂度 $O(nm)$。 ### 二
测试点编号 |
$n$, $m$ |
$k$ |
特殊约定 |
3 |
$\leq 2$ |
$\leq 4$ |
无 |
4 |
$\leq 4$ |
$\leq 7$ |
|
5 |
$\leq 10$ |
||
6 |
对于 $k$ 很小的情况,可以直接进行搜索。 枚举每个待确定的格子内填入的箭头方向并检查合法性,时间复杂度 $O(4^k \cdot nm)$。取决于评测环境,第 5、6 个测试点可能需要少量常数优化。 ### 三
测试点编号 |
$n$, $m$ |
$k$ |
特殊约定 |
11 |
$\leq 200$ |
$\leq 200$ |
$n = 1$ |
12 |
只有一行,看着就很像 DP 的样子…… 用 $f[i][s]$ 表示已经确定了左起前 $i$ 个格子的状态,第 $i$ 个格子中箭头方向为 $s$(取 $1$ 至 $4$ 依次表示上下左右)的方案数。按照第 $i$ 个格子是否是“`.`”分开讨论进行转移。 另一个思路是计算**不包含**连续两个格子依次填入“右、左”的方案数——总之怎么做都可以啦。 ### 四
测试点编号 |
$n$, $m$ |
$k$ |
特殊约定 |
7 |
$\leq 10$ |
$\leq 100$ |
无 |
8 |
|||
9 |
|||
10 |
没有环…… 每个格子有一条出边…… [反向树形图](https://en.wikipedia.org/wiki/Arborescence_%28graph_theory%29)(anti-arborescence)? 要选择某些格子的出边…… [生成树形图](https://en.wikipedia.org/wiki/Spanning_tree#In_directed_multigraphs)?! 我们希望建立一张有向图,使得它得生成树形图与填入箭头的方案一一对应。这样一来,该有向图的生成树形图的数量,即为所求的方案数。 事实上,可以通过下列方式建立这张图: * 将每个格子视作一个节点,并增加一个节点对应整个网格的外部区域; * 对于每一个标有箭头的格子,建立一条由**其对应的节点**连向**其中箭头指向的目标所对应节点**的有向边; * 对于每一个标有“`.`”的格子,建立四条由**其对应的节点**分别连向**四个方向邻居所对应节点**的有向边(保留重边——可能出现在网格的角落位置)。 > 例如,对于样例中的第二组数据: > > ``` > ← ← → → > ← . ← ← > → → . → > ← ← → → > ``` > > 建成的图如下所示。 > > ![sol_2](sol_1.png) 容易发现,这张有向图以**网格外部区域所对应节点**为根的反向生成树形图,与填入箭头的方案一一对应。 按上述方式建立有向图,利用有向图的[矩阵树定理](https://en.wikipedia.org/wiki/Kirchhoff%27s_theorem)计算其生成树形图的数目。时间复杂度为 $O((nm)^3)$。 ### 五
测试点编号 |
$n$, $m$ |
$k$ |
特殊约定 |
13 |
$\leq 200$ |
$\leq 200$ |
有且仅有第 $1$ 行的所有格子中标记未确定 |
14 |
|||
15 |
|||
16 |
$\leq 300$ |
无 |
|
17 |
|||
18 |
|||
19 |
|||
20 |
对于第 13 至 15 个测试点,相当多节点的出边是已经确定的,因此可以通过将不必考虑的点进行收缩,使需要计算的节点数降至可接受的 $O(n)$ 范围,达到 $O(n^3)$ 的时间复杂度,在此不必赘述。其实是王队长说要把这个子任务留着的,你们要知道具体怎么做就去问他吧 对于没有特殊约定的数据亦同理,考虑去除图中不必要的点。 给每个标有“`.`”的格子进行编号,用 (0) 表示网格外围。预处理每个标有“`.`”的格子朝四个方向出发行走时,到达的第一个带有编号的位置。 > 例如,对于样例中的第二组数据: > > ``` > ← ← → → > ← (1) ← ← > → → (2) → > ← ← → → > ``` > > 预处理的结果如下: > > | Source | ← | → | ↑ | ↓ | > |:--:|:--:|:--:|:--:|:--:| > | (1) | (0) | (1) | (0) | (2) | > | (2) | (2) | (0) | (1) | (0) | 将前述的建图方法改变如下: * 将每个标有“`.`”的格子视作一个节点,并增加一个节点对应整个网格的外部区域; * 对于每一个标有“`.`”的格子,建立四条由**其对应的节点**分别连向**四个方向到达的第一个“`.`”格子或网格外围所对应节点**的有向边(保留重边——可能出现在网格的角落位置)。 > 对于样例中的第二组数据,得到的有向图如下: > > ![sol_2](sol_2.png) 这张有向图以**网格外部区域所对应节点**为根的反向生成树形图,仍与填入箭头的方案一一对应。 这种建图方法得到的图的节点数为 $O(k)$,利用矩阵树定理计算生成树形图个数即得答案。时间复杂度 $O(nm + k^3)$。 (另一种殊途同归的思路是直接将已经确定的节点进行收缩,实际得到的图应该是相同的。) ### 六 由于数据范围不大,并不知道是否存在诸如 $O(4^{\sqrt k})$ 或者 $O(4^n)$ 的状压 DP 部分分解法…… 如果对于这份题解有疑问,或者使用了其他奇妙的方式处理本题,也欢迎在群里戳出题人并和大家讨论 :) ## 数据那些事儿 本题数据中的箭头方向主要由四种方式生成:**随机**、**树**、**迷宫**和**同向**。 * **随机**:正如字面意义,随机每个格子的箭头方向。当然这样生成的地图很容易产生环而导致不合法,因此特意避免了相邻两个格子互相指向的情况(然而数据大了还是有很多环 = =)。 * **树**:传入一个参数 `factor`,为 $[0, 1]$ 间的实数。每次取一个网格边界的格子或一个四周有空格的格子,随机行走并沿途标上对应的箭头。每一走步有 `factor` 的概率退出本次循环,当无路可走时也退出本次循环。大部分测试数据由此方法生成。 * **迷宫**:从一个角落开始,每次随机选择一个方向走到底并拐弯。生成的地图大概长这个样子: ``` → → → → → → → → → → ↑ → → → → → → → → ↓ ↑ ↑ ← ← ← ← ← ← ← ↓ ↑ ↓ ← ← → ↓ → ↓ ↑ ↓ ↑ ↓ → ↑ ↑ ↓ ↑ ↓ ↑ ↓ ↑ ↓ ↑ ← ↑ ↓ ↑ ↓ ↑ ↓ ↑ ↓ → ↑ ↑ ↓ ↑ ↓ ↑ ↓ ↑ ↓ ↑ ← ↑ ↓ ↑ ↓ ↑ ↓ ↑ → → → ↑ → ↑ → ↑ ↓ ↑ ← ← ← ← ← ← ← ← ← ``` 这样做的目的是使未记忆化的行走过程达到 $O(n^2 m^2)$ 的上界。而且这样的图超好玩的不是嘛(逃 * **同向**:大部分箭头同向,混入少量随机。不知道有啥用,大概是为了好玩(???) 以上。今天的 Div. 1 第三题,希望大家喜欢 \(?′ω`?\)