“提高模拟能考出省选题来“
题目I——最短路径(path)
题目描述
一个 $N$ 个点,$M$ 条边的有向权值图,求全源最短路中每条边被经过的次数。
最短路径:从 $a$ 到 $b$ 的最短路径是指一条路径当且仅当不存在另一条从 $a -> b$ 的路径比该路径更短。
意思是两点之间的最短路径不止一条
求每条边通过的最短路径的个数。取模 $10^9+7$。
思路I
用 $Spfa$ 跑 $n$ 遍最短路,跑完之后枚举每条边,记录所有满足 $val_i+c_{i,j}=val_j$ 的边。再以此对于每一遍 $Spfa$ 跑一遍 $Topo$ 排序。
思路II
依然是跑 $n$ 遍最短路,求出最短路径图,即只含最短路的边。用 $f_i$ 表示从 $1$ 点至 $i$ 点有多少条路径, $g_i$ 表示从 $i$ 号点往后走有多少条路径。则以 $i$ 为起点的所有最短路中,经过 $c_j(u,v)$ 边的路径条数为 $f_u*g_v$
另话
这道题在洛谷上是双倍经验。一道紫一道灰。这样做 $NOIp$ 模拟的第一题真的好吗
Task One Ac Code
思路I
1 |
|
思路II
1 |
|
题目II——数列(seq)
题目描述
对于一个长度为 $n$ 的数列,有 $m$ 个询问:
- $C\ i\ x$ 表示将下标为 $i$ 的数改为 $x$
- $Q\ i$ 求满足 $\forall i \leq k \leq j,A_k \leq \max\{A_i,A_j\}$ 中 $j$ 的个数
复杂度不大于 $O(n \log n)$
题意思路
根据其查询,我们需要找到所有的“谷段”,即如果我们将整个数列看作一个波峰图,如下图所示:
那么我们就需要找到所有类似于开口向上的二次函数的个数。不难发现:当我们第一次找到 $A_p \leq A_j$ 时,$p$ 到 $j$ 之间的任意位置都是满足要求的。
然而,当第一次:
当 $A_p = A_j$ 时,对于 $j$ 之后下一个满足要求的位置 $k$ 时,$j$ 与 $k$ 之间的任意位置也是可以取的。
而当 $A_p < A_j$ 时,对于 $j$ 之后下一个满足要求的位置 $k$ 时,就仅仅只能取 $k$ 位置了。
其缘由读者可自行思考。
算法思路
又是线段树打爆的一天
使用一种类似分块但胜似分块的神奇思路。
将整个数列分成 $\sqrt n$ 段:
- 对于每一段,维护其向左向右的递增序列;
- 对于相邻的段,维护其向左向右的递增序列。
虽然我觉得这题解类似没写又胜似没写
用 $L_i$ 存储第 $i$ 段的左坐标,$R_i$ 存储第 $i$ 段的右坐标。数组 $Bel_i$ 存储 $i$ 位置所属的段编号。
初始化/修改操作
对于每一段都有一个数 $top$ 和一个数组 $st_i$ 。$st$ 数组存储的是该区间内的最长不下降子序列,而 $top$ 则是 $st$ 数组的长度。然后求就完事儿了,复杂度 $O(\sqrt n)$
1 | inline void underModify(int l,int r,int st[],int &top) |
查询操作
暴力求本区间,复杂度 $O(\sqrt n )$
1 | int ans=0; |
记查询点为 $p$ ,则对于 $Bel_p+1$ 到 $Bel_n$ 的区间操作为:
二分该区间的 $st$ 数组,找到第一个 $l$ 位置满足 $A_p \leq A_l$ ,如果当前 $Max$ 与 $A_p$ 是相等的,则可以计算该区间 $l$ 之前的任意位置;反之,计算 $l$ 之后的个数和(不比 $A_p$ 小的个数),当然,$Max=A_p$ 时也要计算该区间。
然后更改 $Max$ 值,查找下一区间。
1 | for(int i=bl+1;i<=num;++i) |
另话
这道题题意很简单,主要原因还是时间复杂度的问题。我使用线段树二分查找的复杂度不稳定,所以很氢凇被卡了
Task Two Ac Code
查看代码
1 |
|