「2022/04」学习记录

本地备份。

虽然比上个月好很多了(指鸽的篇目少了很多),但是还是卷不过卷王。人麻了就是说。

今年省选前最后一篇更新了。省选加油。

「APIO | CTSC 2007」数据备份

首先有一个贪心。每次找到一个最小的边然后加进去。

但这样的贪心显然是假的,因为加完这条边后相邻的边无法再加。可能不是最优。

但考虑到如果边 \((i,i+1)\) 加进去了。但没有加 \((i-1,i)\)\((i,i+1)\),如果当前不是最优的,那么最优的一定是相邻两条边一起加。

于是如果我们加入了一条边 \((i,i+1)\),且他的贡献为 \(a_i\),那么可以考虑在堆中再加入 \((i-1,i+2)\),贡献为 \(a_{i-1}+a_{i+1}-a_i\)

同样的,对于一个加入的区间 \((u,v)\) 贡献为 \(c\),可以再在堆中加入 \((u-1,v+1)\) ,且贡献为 \(a_{L_u}+a_{R_u}-c\)。设 \(L_u,R_u\) 表示这段前面 / 后面的贡献,可以实时维护。

\(k\) 次即为答案。

「CEOI2014」The Wall

发现最后的最短路一定是包含从 \((1,1)\) 出发到一个格子左上角的最短路。然后我们建出最短路径树,树上的边就是最短路。

接下来考虑把一个点拆成左上、右上、左下、右下四个点。然后互相建一条为 \(0\) 边,如果是原图中的边就按原图边权。

然后这些边不能穿过刚刚建出的最短路树,即要保证这些路径是完整的,且不能跨过边。然后跑最短路,从 \((1,1)\) 左上出发到右下即可。

「CEOI2017」Building Bridges

\(n\) 根柱子依次排列,每根柱子都有一个高度。第 \(i\) 根柱子的高度为 \(h_i\)

现在想要建造若干座桥,如果一座桥架在第 \(i\) 根柱子和第 \(j\) 根柱子之间,那么需要 \((h_i-h_j)^2\) 的代价。

在造桥前,所有用不到的柱子都会被拆除,因为他们会干扰造桥进程。第 \(i\) 根柱子被拆除的代价为 \(w_i\),注意 \(w_i\) 不一定非负,因为可能政府希望拆除某些柱子。

现在政府想要知道,通过桥梁把第 \(1\) 根柱子和第 \(n\) 根柱子连接的最小代价。注意桥梁不能在端点以外的任何地方相交。

其中 \(2 \le n \le 10^5, 0 \le |h_i|,w_i \le 10^6\)

先对 \(w_i\) 做个前缀和 \(s_i\)

\(f(i)\) 表示枚举到 \(i\) 的答案,有 \(f(i) = \min \{ f(j) + (h_i-h_j)^2 + s_{i-1} - s_j \}\)

拆开,得到 \(f(i) = \min \{ f(j) + h_i^2 +h_j^2 - 2h_ih_j +s_{i-1} - s_j \}\)

于是有 \(f(i) = h_i^2 + s_{i-1} + \min \{ -2h_i h_j + f(j) + h_j^2 - s_j \}\)

\(k_i = -2 h_i , b_i = f(i) + h_i^2 - s_i\),则 \(f(i) = h_i^2 + s_{i-1} + \min \{ k_j h_i + b_j \}\)

李超线段树优化,复杂度 \(\mathcal{O}(n \log n)\)

「CEOI2020」Spring Cleaning

如果叶子节点总数为奇数,则无解。

然后选一个不是叶节点的点作为根,记录每个子树内叶子节点的个数。

如果为奇数,意味着这个叶子必须贡献到子树外,则子树 \(u\)\(fa_u\) 的贡献会算一次。

如果为偶数,注意因为所有边必须被选,所以 \(u \rightarrow fa_u\) 的贡献会算两次。

树剖,维护修改一个点后这个点到根节点的路径上的奇偶贡献。答案就是 \(n-2+t_0\)。其中 \(t_0\) 表示子树中贡献为偶数的个数。

「CEOI2020」Star Trek

考虑设 \(dp_u = 0/1\) 表示先手必败/胜。于是转移式为,如果存在一个 \(v\) 满足 \(dp_v=0\),则 \(dp_u =1\)

可以发现,在不同的树间连边的操作相当于把这棵树换根后接上去。所以可以设 \(dp2_u\) 表示换根的结果。

但考虑到一个点接上一个 \(dp_u=1\) 的点不会有改变,但接上一个 \(dp_u=0\) 的点可能会发生改变。

于是设 \(r_u\) 表示有多少个点连接败点后会发生改变。于是记录 \(s0_u\) 表示 \(dp_v = 0\) 的个数。

再定义 \(sr_{u,0/1}\) 表示 \(dp_v = 0/1\)\(r_v\) 的和。

转移。如果 \(s0_u = 0\),说明 \(dp_v\) 全是 \(1\),则就是 \(sr_{u,1}+1\);否则如果 \(s0_u =1\),那么这个有且只有一个为 \(0\) 的点,则贡献为 \(sr_{u,0}\)

换根。然后矩阵乘法优化。

「CF280D」k-Maximum Subsequence Sum

长度为 \(n\) 的数列,支持两种操作:

  1. 修改某个位置的值。
  2. 询问区间 \([l,r]\) 里选出至多 \(k\) 个不相交的子段和的最大值。 一共有 \(m\) 个操作。

对于所有数据,有 \(1 \le n,m \le 10^5,|a_i| \le 500,1 \le k \le 20\)

还有一个 \(l \le k \le r\) 然后没有修改的 300iq 题。不会没写。

先考虑建费用流。建出 \(n+1\) 个点,第 \(i\) 个点向 \(i+1\) 连一条流量为 \(1\),费用为 \(a_i\) 的边。每个点向源点 \(S\) 连边。然后对于询问 \([l,r]\),把 \([l,r+1]\) 的点像汇点 \(T\) 连边;把 \(S\) 拆成 \(2\) 个点中间连一条流量为 \(k\) 的边。

考虑模拟费用流。每次找一条最长路然后增广,反向边流满且费用为负数。在这道题的本质就是,对于区间 \([l,r]\) 求一次最大字段和,然后把找到的字段和 \([x,y]\) 中的所有 \(a_i\) 变成 \(-a_i\)。连续做 \(k\) 次即可。

区间最大字段和区间取负可以用线段树维护。维护一个正数和一个取反的数,取反操作直接交换。注意还要维护最大字段和答案的位置。

「CF578F」Mirror Box

在一个 \(n \times m\) 的网格中,每个格子里都有一个呈 \/ 状的镜子。

一个合法的网格需要满足从任意一个边界段垂直射进网格中,光线会从相邻的边界段射出,同时网格中的每一段都被至少一条光线穿透。

现在网格中有 \(k\) 个位置的镜子形状不确定,求有多少种合法的网格。

对于所有数据 \(n,m \le 100,k \le 200\),答案对质数 \(p\) 取模。

神仙题。

先说结论,把 \(n \times m\) 网格看成 \((n+1) \times (m+1)\) 的点阵。然后把他黑白染色。放镜子相当于在两个同色的点之间连边。答案是黑点连成一颗生成树或者白点连成生成树的方案数。

于是只要对于点阵相邻的颜色对角线连边。然后把题目给出的边用并查集合并,跑 Matrix-Tree 就行了。

为什么?

首先注意到,每一段都必须有至少一条光线,同时一个被镜子割成两块的方格的两边也必须有光线。这意味这不能有环。

第二个条件是,边界分成相邻的组。注意到(?)如果一个点连成了生成树,其他点只有一种连发。

「CF983D」Arkady and Rectangles

所以为什么没有染色的地方也算一种颜色的(?

这题是在 「数据结构 2022/02 」学习记录 中的最后一题。是谁写的时候自己的题解都看不懂了啊,是我啊那没事了。

「CF1408H」Rainbow Triples

给定长度为 \(n\) 的序列 \(p\)

找出尽可能多的三元组 \((a_i,b_i,c_i)\) 满足:

  • \(1 \le a_i < b_i < c_i \le n\)
  • \(p_{a_i}=p_{c_i}=0,p_{b_i} \neq 0\)
  • \(p_{b_i}\) 互不相同。
  • 所有的 \(a_i,b_i,c_i\) 互不相同。

输出最多可以选出多少个三元组,多组数据。

其中 \(\sum n \le 5 \times 10^5\)

寄。刚开始建了一个网络流然后死活不知道怎么优化。结果开题解一看,别人建的网络流优美简洁,我建的网络流就一个傻逼。

首先设 \(0\) 的个数为 \(c_0\)。注意到答案的上限为 \(\left\lfloor \frac{c_0}{2} \right\rfloor\)。于是考虑把左半边的 \(\left\lfloor \frac{c_0}{2} \right\rfloor\)\(0\) 分一组,右边剩下的为一组,叫做 LR。于是对于一个非 \(0\) 的数 \(p_i\),他左边的 \(0\)L 组的,右边的选 R 组的一定最优。

注意到相同的 \(p_{b_i}\) 只能取一个,不妨看成颜色。对于一种颜色 \(x\),设 \(L_x\) 表示在 L 组中最右的,\(R_x\) 表示在 R 组中最左的。先贪心的选这两个点,如果不行一个向左调整一个向右调整。

建网络流。源点 \(S\) 对每个颜色连一条流量为 \(1\) 的边。然后放一层颜色为 \(0\) 的点,在 L 组的都往左连,在 R 组的都往右连,流量为 \(\infty\),于是对于一个颜色 \(x\),连边 \(L_x,R_x\),流量为 \(1\)。然后全部 \(0\) 点像汇点 \(T\) 连边。

模拟网络流。因为最大流等于最小割。那么答案显然不可能割颜色到 \(L,R\) 的边,于是答案一定是割了一些颜色,割了一段 \(0\) 点到 \(T\) 点的边的一段前缀和后缀。

又注意到,割掉 \(S\) 到颜色的边当且仅当这个颜色没被 \(T\) 那边的割边覆盖。

于是枚举割掉的前缀,线段树维护 R 组的颜色,当颜色 \(x\)\(L_x\) 覆盖的时候,则对 \(R_x\) 后缀的答案减去 \(1\)

复杂度 \(\mathcal{O}(n \log n)\)

纪念一下。当时看完题目后想去看看 cf 的排行,然后打开好友排行我大受震撼。

然后我写了 H 后。伟大的 defkaeru 去写了 E 来凑排行:

1.png

然后 cf 排序比较阴间,强迫症震怒。我们进行一个 p 图。

2.jpg

「CF1415F」Cakes for Clones

一条数轴上有一个人,他的移动速度为 \(1\),每个时刻他可以让自己的坐标从 \(x\) 变为 \(x \pm 1\)、或者保持 \(x\) 不变。

当他位于整点上时,他可以放置一个无法移动的分身,同时摧毁已经存在的分身(如果存在),放置分身不消耗时间。

初始时他位于 \(0\),现在有 \(n\) 个任务,每个任务 \((x_i,t_i)\) 要求他在 \(t_i\) 时刻要么本人要么分身在 \(x_i\) 坐标处。

问是否存在合法方案,存在输出 YES,否则输出 NO

其中 \(1 \le n \le 5000\)

妙妙 DP。首先肯定按时间排序。设 \(mi_i\) 表示当前在第 \(i\) 个点,前面所有的点都可以用本人或者分身接住。设 \(dp(i,j)\) 表示当前在 \(i\),分身留给后面的 \(j\) 是否可行。

转移,分类。

  • 如果分身在当前 \(i\) 放下时,即意味着分身应该在 \(mi_i\) 的时候分下。

    • 直接走到 \(i+1\)。则 \(mi_{i+1} \leftarrow \operatorname{min}(mi_{i+1},\max(mi_i+|x_i-x_{i+1}|,t_i))\)
    • 先走到后面的点,然后把分身更新到后面的一个点,然后再回到 \(i+1\)。这里更新 \(dp(i,j)\)。设走到 \(j\),那么过去的时间是 \(mi_i+|x_i-x_{i+1}|\),但需要注意的是,因为分身必须在 \(t_i\) 时刻在 \(x_i\),所以如果先到了 \(j\) 也必须至少等分身在 \(i\) 完成任务。则 \(dp(i+1,j) \leftarrow [\max({t_i,mi_i+|x_i-x_j})+|x_j-x_{i+1}| \le t_{i+1}]\)
  • 当前不放分身,意味着当前点必须在 \(t_i\) 时刻。

    • 分身不给 \(i+1\)。等完直接过去。则 \(dp(i+1,j) \leftarrow dp(i+1,j) \cup dp(i,j)\)
    • 分身给 \(i+1\)。那么可以直接放完分身走到 \(i+2\),则 \(mi_{i+2} \leftarrow \operatorname{min}(mi_{i+2},\max(t_{i+1},t_i+|x_i-x_{i+2}|))\)。或者走到后面放下分身再回来,这个和上面那个差不多,不写了。

注意转移都要保证能走到。如果 \(mi_i \ge t_i\) 的时候不要直接判无解,跳过本次转移即可。

「CF1500C」Matrix Sorting

给你两个 \(n \times m\) 的矩阵 \(A,B(1 \le n,m \le 1500)\),矩阵的元素均为 \([1,n]\) 内的整数。

每一次操作你可以选定一列作为每一行的关键字,按照关键字从小到大的顺序把所有行排序得到一个新矩阵。这里使用的排序是稳定的,即如果有两行的关键字相同,则按照在原矩阵的先后顺序排序。

你可以进行不超过 \(5000\) 次操作,问你能否将 \(A\) 变成 \(B\),不能变成输出 -1,否则输出一种可行的操作序列。

又看错题了。(?

交换每一行对比每一行可以哈希。对于在 \(B\) 中的一行在 \(A\) 所对应的一行记为 \(t_i\)\(A\) 中的一行对应 \(B\) 中的就是 \(c_i\)

最后 \(B\) 中的排序一定是 \(1 \sim n\)

于是对 \(A\) 排序的时候,只要保证第 \(t_i\) 行在第 \(t_{i+1}\) 行前面就可以了。于是扫描每一个列,如果 \(a_{t_i,j}<a_{t_{i+1},j}\) 那么就可以排序好,如果是 \(>\) 就会反过来,\(=\) 不影响。

如果可以排好,那么怎么执行都不会更劣。如果反过来,那么之后必须存在一个可以让他再正过来的操作。用队列维护这个先后顺序,然后拓扑排序即可。

「ExPR #1」乘积

给定两个正整数 \(n,m\)

你有一个正整数 \(M\),初始 \(M=1\)。你将进行若干次操作,每次在 \([1,n]\) 中均匀随机选取一个整数 \(x\),并令 \(M:=M\times x\)。当 \(M>m\) 时停止操作。

求期望进行多少次操作。

可以证明,答案一定为有理数。设其为 \(\frac{a}{b}\)\(a\)\(b\) 为互质的正整数,数据保证 \(b\) 不为 \(998244353\) 的倍数),则你需要输出一个整数 \(x\) 满足 \(0\le x<998244353\)\(a\equiv bx \pmod{998244353}\)。可以证明这样的 \(x\) 唯一存在。

其中 \(2 \le n \le 9 \times 10^8,1 \le m \le 10^9\)

首先平方级别的 dp 显然。但注意到我们逐个乘和逐个除本质是相同的。于是有 \(f(i) = 1 + \dfrac{1}{n} \sum\limits_{j=1}^n f(ij)\)

注意到 \(i>m\)\(f\) 全都为 \(0\)。那么意味着对于 \(\left\lfloor \dfrac{m}{i} \right\rfloor\) ,不妨设 \(g(i)\) 表示 \(M=1,m=i\) 的答案,于是有转移:

\[g_i = 1 + \dfrac{1}{n} \sum\limits_{j=1}^n g ( \left\lfloor \frac{i}{j} \right\rfloor ) \]

整除分块,然后记搜即可。

「ExPR #1」下降

原题:「JOISC 2020 Day2」遗迹

有一个长度为 \(2n\) 的高度序列 \(h\),其中 \(1\sim n\) 每个数都恰好出现了 \(2\) 次。

之后进行了若干次操作,每次操作会让满足存在 \(i<j\)\(h_i=h_j\)\(i\)\(h\) 减一。如果 \(h\)\(0\) 则不再下降。

当进行了足够多次操作后,我们可以证明,会有恰好 \(n\) 个位置的 \(h\) 不为 \(0\),且他们的值恰好为 \(1\sim n\) 各一次。

现在给定你这 \(n\) 个位置 \(p_1,p_2,\cdots,p_n\),你需要求出满足这样的条件的 \(h\) 的个数模 \(10^9+7\) 的值。

其中 \(1 \le n \le 500,1 \le p_i \le 2n\)\(p_i\) 严格递增。

假设已经知道了每个高度 \(h_i\) ,如何判定最后是否能留下?暴力枚举每个数每次从后往前,如果前面存在这个数就 \(-1\),否则保留。如果找不到可以保留的位置说明他会被删。注意到前面保留过的数永远不会被删。

不妨把两个 \(i\) 看成两个不同的数,最后方案数除以 \(2^n\) 即可。

于是设 \(f(i,S)\) 表示,枚举到了第 \(i\) 位,当前被占的位置状态为 \(S\) 的方案数。

发现这个转移,如果找到一段连续的 \(1\),而且是前缀 \(1\),于是设 \(f(i,j)\) 表示枚举到 \(i\),前缀 \(1\)\(j\) 的个数。

\(c_2\) 表示当前状态之前,没有留下的的个数。而 \(c_1\) 表示留下的。

转移,不留下这个位置,则 \(f(i,j) \leftarrow f(i + 1,j) \times (j - c)\)

如果留下,那么这个位置的贡献可能当前无法贡献到前缀,但是可能在未来某个状态开始贡献。于是对于当前位置,有 \(f(i,j) \leftarrow f(i,j) + f(i+1,j)\)

对于未来某个状态,有 \(f(i,j+k) \leftarrow f(i,j+k) + f(i+1,j) \times \dbinom{c_1-j}{k-1} \times g(k-1) \times (k+1)\)

表示在未来时刻,直接贡献了 \(k\) 个前缀,那么在剩下的 \(1\) 中选出 \(k-1\) 个且全部放满的个数 \(g(k-1)\),然后把第 \(k\)\(1\) 放进去,有 \(k+1\) 个选法。

考虑 \(g(k)\) 的算法。考虑设 \(h(i,j)\) 表示考虑到第 \(i\) 个,填满了 \(j\) 个的方案数。

于是有 \(h(i,j) = h(i-1,j) + 2j \cdot h(i-1,j-1) + j(j-1) \cdot h(i-1,j-2)\)

逐个递推即可。复杂度 \(\mathcal{O}(n^3)\)

「JOISC 2020 Day1」建筑装饰 4

给定长度为 \(2n\) 的两个序列,分别为序列 \(A:A_1,A_2,\dots,A_{2n}\),和序列 \(B:B_1,B_2,\dots,B_{2n}\)

构造一个长度为 \(2n\) 的序列 \(C\)。满足以下条件:

  • 序列 \(C\) 的第 \(i\) 个数 \(C_i\),只能从 \(A_i\)\(B_i\) 中选取。
  • \(a\) 为序列 \(A\) 中元素被选取的次数,\(b\) 为序列 \(B\) 中元素被选取的次数,则 \(a=b=n\)
  • 该序列是一个单调上升的序列,不要求严格单调上升

如有多解,任意输出一组解即可。

其中 \(1 \le n \le 5 \times 10^5,1 \le A_i,B_i \le 10^9\)

首先有一个很显然的 \(\mathcal{O}(n^2)\) 的 DP。设 \(f(i,j,0/1)\) 表示当前选到 \(i\),其中 \(A\) 已经选了 \(j\),当前位置为 \(A/B\) 时有无解。

然后可以发现,转移的时候都是连续一段 \(j\) 转移的,且状态都是 \(0/1\)。考虑压缩这一段。

\(f(i,0/1)\) 表示选到第 \(i\) 位,当前选的是 \(A / B\) 的合法情况时,\(A\) 的数量的最大值。\(g(i,0/1)\) 同理,为 \(B\) 的最大值。

于是转移的时候,类似的,判断一下当前和前一位的大小然后分类转移就行了。

求方案的时候就把 DP 倒着走一遍,判断每次选的是那个解。

复杂度 \(\mathcal{O}(n)\)

「JOISC 2020 Day1」扫除

考虑只有 H 操作,发现相当于对 \(x\) 坐标在 \([0,l]\) 内的所有点的 \(y\) 坐标对 \(n-l\)\(\max\)。于是可以把所有询问离线下来,然后维护每个点最大值就行了。

如果有 HV 操作。这两个操作之间会相互影响。观察一下,两个操作之间的影响,假设先执行 \(h_l\) 再执行 \(v_l\),那么对于 \(v\) 的影响,就是 \([0,0] \sim [h_l,v_l]\) 中的数不会受到 \(v\) 的影响。

于是可以发现,如果我们能处理出每个操作会修改的区间,那么所有操作就独立。

对于每个操作的影响,发现是对一段区间进行取最大值。可以用永久标记的线段树来维护。

对于插入的情况,考虑线段树分治。复杂度 \(\mathcal{O}((m+q) \log q \log n)\)

「JOISC 2020 Day2」变色龙之恋

不妨先考虑查询二元组的情况,如果当前二元组返回的是 \(1\),意味着,要么他们有一个喜欢对方,要么刚好同色。如果把这些二元组为 \(1\) 的连边,那么一个点的度数为 \(1\)\(3\)

那么对于性别 X 的 \(i\) 向性别 Y 的 \(j\) 连边后,点 \(j\) 的入度一定为 \(1\) 或者 \(3\)。如果是 \(1\) 就是同色,否则三个点通过两两和当前点查询来判断。

假如我们已经知道了他们的性别,那么图是一个二分图。可以通过二分一边前缀的方法快速查询。

那如果不知道他们的性别,那问题就是当前点是在二分图的那一边。对于当前点,只要对两边一起做一次二分,看看哪边没有特殊点就是属于哪边的。

「JOISC 2020 Day2」有趣的 Joitter 交友

注意到,对于一个强连通分量,设他的大小为 \(m\),他的答案是 \(m(m-1)\)

set 维护,当前连通分量的点,这个分量连向的其他分量,其他分量连向这个分量的分量。

加入边时候,如果两个强连通分量的反向边已经连了,那么直接合并这两个强连通能量。否则先记录一下不合并。

合并的时候,可能会引起其他的合并,于是用一个队列每次记录要合并的点。

「JOISC 2020 Day4」传奇团子师傅

你是一位糯米团子大师,现在你正在串团子。

你面前有一个 \(R\)\(C\) 列的网格,每格里面放着一个粉、白、绿三色之一的团子。你每次会横向、竖向或斜向选三个连续的团子并将他们按顺序串到一起。其中,按顺序指竖直方向的团子只能以上、中、下或下、中、上的顺序串,而不能以中、上、下或中、上、下的顺序串,其他顺序以此类推。这样,你就获得了一串团子。

当且仅当一串团子的颜色顺序是绿、白、粉或粉、白、绿时,我们把这串团子称为美丽串,请求出串取最多的美丽串的方法。

模拟退火提答。

发现这玩意儿是一般图最大独立集。建出图,然后先跑出一组独立集,然后随机删点加新边。

贴个代码备份:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdlib>
using namespace std;
const int N=500+5,M=N*N*8;
const int dx[4]={0,1,1,1},dy[4]={1,0,1,-1};
const char c[4]={'-','|','\\','/'};
struct edge{
	int v,nx;
}e[M];
struct point{
	int x,y,d;
}p[M];
int n,m,ne,tot,ans,f[M];
bitset<M> is,vis,use;
char s[N][N];
vector<int> vc[N][N];
int rd(int x){return 1ll*rand()*rand()%x+1;}
void read(int u,int v)
{	e[++ne].v=v;
	e[ne].nx=f[u];
	f[u]=ne;
}
void add(int x,int y)
{	for(int k=0;k<4;k++)
	{	int xi=x+dx[k],yi=y+dy[k],xj=x-dx[k],yj=y-dy[k];
		if(xi<1||yi<1||xi>n||yi>m||xj<1||yj<1||xj>n||yj>m)continue;
		if(s[xi][yi]=='W'||s[xj][yj]=='W'||s[xi][yi]==s[xj][yj])continue;
		p[++tot]=(point){x,y,k};
		for(int i=0;i<(int)vc[x][y].size();i++)read(tot,vc[x][y][i]),read(vc[x][y][i],tot);
		for(int i=0;i<(int)vc[xi][yi].size();i++)read(tot,vc[xi][yi][i]),read(vc[xi][yi][i],tot);
		for(int i=0;i<(int)vc[xj][yj].size();i++)read(tot,vc[xj][yj][i]),read(vc[xj][yj][i],tot);
		vc[x][y].push_back(tot),vc[xi][yi].push_back(tot),vc[xj][yj].push_back(tot);
	}
}
bool check(int u)
{	if(use[u])return 0;
	for(int i=f[u];i;i=e[i].nx)
	{	int v=e[i].v;
		if(use[v])return 0;
	}
	return 1;
}
int solve()
{	int res=0;
	for(int i=1;i<=tot;i++)
		if(check(i))use[i]=1,res++;
		
	return res;
}
int del(int u)
{	use[u]=0;
	int res=0;
	for(int i=f[u];i;i=e[i].nx)
	{	int v=e[i].v;
		if(check(v))use[v]=1,res++;
	}
	return res;
}
int upd()
{	use=vis;
	int res=0;
	while(1)
	{	int u=rd(tot);
		if(use[u])continue;
		use[u]=1,res++;
		for(int i=f[u];i;i=e[i].nx)
		{	int v=e[i].v;
			if(use[v])res+=del(v)-1;
		}
		break;
	}
	return res;
}
void sa()
{	ans=solve(),is=vis=use;
	int res=ans,rres=0;
//	printf("%d\n",ans);
	double T=6,data=0.999995,k=16;
	while(ans<46500)
	{	rres=res+upd();
		if(rres>=res)
		{	if(rres>ans)ans=rres,is=use,printf("%lf %d\n",T,ans);
			vis=use,res=rres;
		}
		else if(exp(k*(rres-res)/T)*(2e9)>rd(2e9))vis=use,res=rres;
		T*=data;
	}
}
int main()
{	freopen("06.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(s[i][j]=='W')add(i,j);
	sa();
//	for(int i=1;i<=tot;i++)
//		if(is[i])printf("%d %d %d\n",p[i].x,p[i].y,p[i].d);
	freopen("06.ans","w",stdout);
	for(int i=1;i<=tot;i++)
		if(is[i])s[p[i].x][p[i].y]=c[p[i].d];
	for(int i=1;i<=n;i++)printf("%s\n",s[i]+1);
	return 0;
}

「JOISC 2020 Day4」首都城市

考虑点分治。把当前点的颜色设为首都的代价。如果有颜色在当前分治子树外就跳过。否则把所有该颜色的点到当前点的路径上所有颜色都加入的代价。

向上跳的时候如果碰上已经加过颜色就直接跳过。

「JOISC 2020 Day4」治疗计划

\(f(i)\) 表示使 \([1,i]\) 的居民健康的最小代价,于是有

\[f(i) \leftarrow \min \{ f(j)+c_j \} (r_j - l_i +1 \ge |t_i -t_j|) \]

然后有个奇妙优化。

把条件拆一下 \(t_i - t_j \le r_j - l_i+1\) 或者 \(t_j - t_i \le r_j - l_i +1\)

也就是 \(l_i + t_i \le t_j +r_j +1\) 或者 \(l_i -t_i \le r_j - t_j +1\)

类似 dijkstra,把每个 \(f(i)\) 放进优先队列里,每次取出后给能转移到的赋值,也就是取 \(\min\)。我们开一个线段树,存储每个点的上限 \(l_i + t_i\) 或者 \(l_i - t_i\)。然后每次找的时候对比对应上限,如果更新了就放进优先队列里。

注意到每个点只会被更新一次,那么线段树的复杂度可以保证,于是复杂度 \(\mathcal{O}(n \log n)\)

「JOISC 2022 Day1」错误拼写

从前,K 总统有着一个长度为 \(N\) 的字符串 \(S\),仅由小写字母组成。然而,他忘记了它。
他还有一个词典,其中包含了各式各样的错误拼写。而他曾看过那本词典,现在他确认到 \(S\) 满足以下条件:

  • \(T_i\) \((1\le i\le N)\)\(S\) 删去第 \(i\) 个字符并将前后字符相接所得的字符串。对于每个 \(j\) \((1\le j\le M)\) 满足 \(T_{A_j} \le T_{B_j}\)

其中 \(T_{A_j} \le T_{B_j}\) 表示 \(T_{A_j}\) 等于 \(T_{B_j}\)\(T_{A_j}\) 在字典序上小于 \(T_{B_j}\)

请写一个程序,对于 K 总统给定的如上关于 \(S\) 的信息,输出可能的 \(S\) 的个数,对 \(10^9+7\) 取模。

考虑题目给的约束相当于什么。考虑约束删掉了 \(l\)\(r\),不妨设 \(l<r\)。注意到 \(1 \sim l-1\)\(r+1 \sim n\) 是一样的。所以比大小相当于比 \([l,r-1]\)\([l+1,r]\)。于是一定是开头一段都是相同的字符,然后在一个位置出现了一个字符比前面更小。如果是 \(l>r\) 的情况就更大。

考虑 DP。设 \(f(i,j)\) 表示从 \(i\) 的后缀,第 \(i\) 个字符是 \(j\) 的方案数。倒着转移。

转移的时候枚举一个 \(k\),设他比 \(j\) 大。考虑约束的影响,对于约束条件 \((l,r,<)\) 如果 \(l \in [i,k)\),那么 \(r\) 跨过 \(k\)。如果小也同理。

于是可以用一个堆维护可以转移的点,然后分别记录堆内 \(<\)\(>\) 情况转移的前缀 / 后缀和。

「JOISC 2022 Day1」京都观光

京都是世界级的观光圣地,它也被称为网格城市。你来到了京都观光,并且你计划步行游览一个著名的景点。本题中,我们考虑如下的简化问题。

在城市中,有 \(H\) 条东西方向的街道和 \(W\) 条南北方向的街道,因此城市是一个 \((H-1)\times(W-1)\) 的网格。从北数第 \(i\) 条街道和从西数第 \(j\) 条街道的交叉点记作路口 \((i,j)\)

不同的街道可能有不同的材质、宽度和拥挤程度,因此你的步行速度有可能不同。对于每条街道,你的步行速度如下:

  • 如果你在从北数第 \(i\) 条街道上行走单位长度,需要 \(A_i\) 秒。即从路口 \((i,c)~\left(i\in[1,H],c\in[1,W)\right)\) 走到路口 \((i,c+1)\) 需要 \(A_i\) 秒。

  • 如果你在从西数第 \(j\) 条街道上行走单位长度,需要 \(B_j\) 秒。即从路口 \((c,j)~\left(c\in[1,H),j\in[1,W]\right)\) 走到路口 \((c+1,j)\) 需要 \(B_j\) 秒。

你现在在路口 \((1,1)\),你想前往 \((H,W)\),你必须沿着街道行走,并且你不希望走远路,即你不会向北或向西走。

你希望尽早到达目的地,请你求出,在给定的条件下,从路口 \((1,1)\) 前往路口 \((H,W)\) 所需的最少时间。

考虑什么情况某些边是没有贡献的。设五个值分别为 \(a_i,a_{i+x},b_{j-y_0},b_j,b_{j+y_1}\)。考虑什么时候中间的贡献最劣,右边的路线和中间的差为 \(x(b_{j}-b_{j+y_1})-y_1(a_{i+x}-a_i)\),左边的为 \(x(b_{j-y_0}-b_j) - y_0(a_{i}-a_{i+x})\)

然后要中间最劣,意味着这两个差都要大于 \(0\)

观察这个形式,发现他很向量叉乘。于是设 \(\overrightarrow{a}=(a_{i}-a_{i+x},x), \overrightarrow{b}=(b_{j-y_0} - b_j,y_0),\overrightarrow{c}=(b_j-b_{j+y_1},y_1)\)

于是有 \(b \times a > 0,-c \times a> 0\)。说明 \(b\)\(a\) 顺时针,\(c\)\(a\) 逆时针。所以 \(b\)\(c\) 顺时针方向。

于是我们对所有的 \(b\) 求一个下凸壳就行了。同理 \(a\) 也求一个下凸壳。

然后看着两个凸壳。发现就是在两个凸壳上走,于是对两个凸壳做一个闵可夫斯基和的凸壳即可。

「JOISC 2022 Day2」团队竞技

JOI 大学有 \(N\) 只海狸,他们都参与竞技编程。每只海狸有三项能力值:思考值,行动值和运气值。如果一个能力值很大,意味着他这项能力比较强大。对于第 \(i~(i\in[1,N])\) 只海狸,他的思考值为 \(X_i\),行动值为 \(Y_i\),运气值为 \(Z_i\)

今年 JOI 大学的海狸们将参与一场团体竞技编程,一支队伍由三名队员组成。Bitaro 是 JOI 大学的教练,由于团队合作很重要,Bitaro 决定从 \(N\) 只海狸中选出三只海狸组成队伍,这三只海狸要满足以下条件:

条件:每个成员都有自己的优势,这意味着每个成员都有一项能力值严格大于其他两人的对应能力值。

在所有符合条件的组队中,Bitaro 想要选一个总能力最强的队伍,一个队伍的总能力定义为:三人最大思考值,三人最大行动值和三人最大运气值之和。

请你求出,是否存在一个符合条件的组队,如果是,计算队伍总能力可能的最大值。

考虑按照 \(z\) 从小到大排序。然后一个个加入 set 维护满足条件的最大 \(x,y\) 的值。

对于每次更新,如果他可以刷新最大的 \(x,y\) 就加入,然后判断在 set 里查询 \(y\) 是否能更大即可。

「JOISC 2022 Day3」洒水器

JOI 君有多年在自家菜园种植蔬菜的经验,现在他计划管理 IOI 农场。

IOI 农场由 \(N\) 块土地组成。土地间有 \(N-1\) 条双向道路相连,编号从 \(1\)\(N-1\),第 \(i\) 条道路连接土地 \(A_i\)\(B_i\),任意两块土地间都可以通过道路互达。农场的每块土地上都有一个洒水器,使用洒水器可以向附近的土地洒水。

JOI 君计划在 IOI 农场种植 JOI 谷。JOI 谷是一种奇特的作物,它在被浇水时高度会立刻发生变化。但是同时,JOI 谷是一种脆弱的植物,若它的高度大于等于 \(L\),JOI 谷顶部长为 \(L\) 的部分会立刻断裂并掉落。JOI 君会收获掉落的部分。

初始时,JOI 君在土地 \(j\) 上种了一株高度为 \(H_j\) 的 JOI 谷,之后的 \(Q\) 天,JOI 君都会照料这些 JOI 谷,在第 \(k\) 天,JOI 君会做如下两个操作之一:

  • 操作 \(1\):JOI 君使用土地 \(X_k\) 上的洒水器,向与土地 \(X_k\) 距离不超过 \(D_k\) 的土地上浇水,使这些土地上的 JOI 谷高度乘以 \(W_k\)。由于 JOI 谷会不断断裂,因此若对一株原高度为 \(h\) 的 JOI 谷洒水,它的高度会变为 \(hW_k\bmod L\)
  • 操作 \(2\):JOI 君测量土地 \(X_k\) 上 JOI 谷的高度。

土地 \(x\) 和土地 \(y\) 间距离的定义为:从土地 \(x\) 前往土地 \(y\) 经过道路数的最小值。

JOI 君希望 JOI 谷按照计划长大,因此,他希望提前算出每次操作 \(2\) 应当测量出 JOI 谷的高度。

注意到深度很浅。所以设 \(t(u,d)\) 表示对于第 \(u\) 个点的第 \(d\) 个父亲打的标记(乘积)。于是每次穿标记再向上跳 \(d\) 个父亲就可以了。答案就是当前点的 \(40\) 个父亲的标记乘积。

「JOISC 2022 Day4」复兴计划

JOI 镇是一个曾经辉煌的工业区。为了运输产品,其中建起了许多铁轨与火车站。尽管 JOI 镇已经衰落,那里仍有许多不再被使用的铁轨与火车站。

JOI 镇中有 \(N\) 个火车站,编号为 \(1,2,\dots,N\)。其中还剩下 \(M\) 条铁轨。第 \(i\) 条铁轨 \((1\le i \le M)\) 双向连接火车站 \(A_i\)\(B_i\),且其宽度为 \(W_i\)。保证能够从任意火车站经过若干条铁轨到达任意其他火车站。

你是 JOI 镇的镇长。你计划吸引铁路公司来使用 JOI 镇中留下的铁轨与火车站,使得 JOI 镇复苏成为「铁路之镇」。

于是,共有 \(Q\) 个铁路公司申请参与这个复兴计划。然而,不同公司的火车所需的铁轨宽度也有所不同。这意味着你需要重建这些铁轨,使得它们都匹配对应公司的火车。

\(j\) \((1\le j\le Q)\) 家铁路公司的火车所需的铁轨宽度为 \(X_j\)。为了迎合公司 \(j\),要求满足以下条件:
条件:保证能够从任意火车站只经过宽度为 \(X_j\) 的铁轨到达任意其他火车站。

为了满足上述条件,你可以按如下方式重建铁轨任意次:
重建:选择一条铁轨,你可以重建其使得其宽度增加或减少 \(1\) 并花费 \(1\)。然而,若其宽度为 \(1\),则不能再减少其宽度。

为了确定你能满足哪些公司,你需要求出迎合公司 \(j\) 所需要的最小花费。

请写一个程序,对于给定的火车站、铁轨与铁路公司的信息,计算迎合公司 \(j\) 所需要的最小花费。

首先会想到需要处理出每条边在生成树出现的时间,因为他一定是一段连续的区间。

所以当一个生成树改变的时候,当且仅当,生成树外的一点比他在的链上的一条边小。所以这条边会被替换当且仅当这两条边的平均数时刻会被替换。

注意到 \(n\) 很小,所以可以直接把边从小到大排序,然后每次计算加入第 \(i\) 条边时,前 \(i-1\) 条边组成的生成树哪条边和这条边会第一个相互替换,此时记录下替换时间,并且把这条边加进去就行。

然后知道了每个时间后记录下这个一次函数形式贡献的前缀和。按照这条边不出现贡献的时间排序,询问的时候做前缀和即可。

「JOISC 2022 Day4」一流团子师傅

JOI 君是一位专业的团子师傅。在 JOI 君的店里,团子的颜色很有讲究。一共有 \(N\) 种颜色,编号为 \(1,2,\dots,N\)

一流团子串是 JOI 君的店里的招牌食品。制作一个一流团子串,需要将 \(N\)颜色不同的团子串在一根竹签上。

对于每一种颜色,JOI 君都制作了 \(M\) 个这种颜色的团子。因此,JOI 君总共有了 \(NM\) 个团子。这些团子被编号为 \(1,2,\dots,NM\)。使用这些团子和 \(M\) 根竹签,JOI 君希望串出 \(M\) 个一流团子串。

为了避免在颜色上犯错误,JOI 君将会启用他的团子检测器。如果 JOI 君输入一些团子的编号,团子检测器会返回使用这些团子能制作的一流团子串的个数的最大值。当然,前提是充分使用竹签。

JOI 君希望能通过使用若干次团子检测器将 \(NM\) 个团子分为 \(M\) 组。其中,每一组包含 \(N\) 个团子,且每种颜色的团子恰有一个。

JOI 君想在使用不超过 \(50\,000\) 次团子检测器的前提下完成这件事。

请写一个程序,对于给定的团子的信息,实现 JOI 君使用不超过 \(50\,000\) 次团子检测器来完成任务的策略。

首先可以从左到右前缀二分出第一个出现 \(>0\) 位置,这个位置的颜色就是这个颜色第一次出现的位置。

剩下的考虑直接暴力判,\(3\)\(3\) 个跳。在做这些之前 shuffle 一下。

「JOISC 2022 Day4」鱼 2

JOI 君有 \(N\) 条鱼,编号为 \(1,2,\dots,N\)。第 \(i\) \((1 \le i \le N)\) 条鱼的大小为 \(A_i\)

当我们养鱼的时候,需要注意如下的一个事实:如果有两条鱼离得很近,那么随着时间的流逝,可能会有其中一条吃掉另一条。其中,两条鱼离得很近,当且仅当它们中间没有鱼。
更具体地,如果鱼 \(x\) 的大小不小于鱼 \(y\) 的大小,且鱼 \(x,y\) 离得很近,那么 \(x\) 可以吃掉 \(y\),且 \(x\) 的大小变为原来 \(x,y\) 的大小之和。如果 \(x,y\) 一样大,那么 \(x\) 吃掉 \(y\)\(y\) 吃掉 \(x\) 都可能发生。

JOI 君会养 \(Q\) 天鱼。为了消磨时光,他会进行如下的思想实验。在第 \(j\)\((1 \le j \le Q)\),JOI 君会进行如下行动中的一个:

  • 第一类:JOI 君给鱼 \(X_j\) 吃了某些秘制的食物。这会将鱼 \(X_j\) 的大小变为 \(Y_j\)

  • 第二类:JOI 君将编号在区间 \([L_j,R_j]\) 内的鱼单独拿出来,并进行以下实验:
    JOI 君将鱼 \(L_j,L_j+1,\dots,R_j\) 从左到右依次放在一个鱼缸中。由于鱼们具有如上所述的特点,最后只有一条鱼会存活。存活的这条鱼的编号取决于在哪些时刻哪些鱼吃掉了哪些鱼。JOI 君想知道可能成为最后存活者的鱼的条数。在实验中,鱼的编号不会改变,也不能有两条鱼同时吃掉同一条鱼。

请写一个程序,对于给定的 JOI 君的鱼和实验的信息,计算每个第二类行动的答案来让 JOI 君能够证明或证伪自己的观点。注意这只是思想实验,并没有任何鱼真的被吃掉。

首先注意到,对于不同的鱼,如果他们吃掉了同一个极长区间,那么他们就会变成同一种情况。

于是自然的想到用线段树维护当前区间内鱼的能吃的极长区间对应的数量。然后对于线段树的一段区间,只要维护能吃到左端点,和能吃到右端点的极长区间。中间的可以递归下去。

然后注意到,如果一个前缀吃一半蚌埠住了,那意味着这段的前缀和翻倍了所以没法吃。这点说明了这样的区间只有 \(\mathcal{O}(\log v)\) 个。

于是就可以暴力合并。合并判断的方法也可以用前缀和来判断。

然后线段树合并的时候,先把前后缀和完整的前后段合并,就合出了当前区间的前后缀。

然后对于左区间的后缀和右区间,可以双指针维护。

「POI2004」JAS

神秘贪心题。本题相当于要求一个深度最浅的点分树。再次转化题意,每个点上有一个 \(d_u\),且需要满足两个 \(d\) 值相同的点 \(u,v\) 在点分树上的 \(\operatorname{lca}\)\(d\) 值比这两个点大。最小化最大的 \(d\)

注意到,如果我们跑点分治的话,虽然这不是最优的,但答案是 \(\log\) 级别,所以这里 \(d\) 的答案一定也是 \(\log\) 级别且更小。

于是考虑状压。对于每个点设 \(S_u\) 表示 \(u\) 子树内所有可能不满足条件的 \(d\)

于是对于一个点 \(u\) 和他子树内的第一点 \(v\)\(S_u\) 意味着 \(u \rightarrow v\) 上不存在一个点 \(p\) 使得他的 \(d_p > d_u\)\(d\) 集合。考虑合并两个子树 \(v_1,v_2\) 时,这意味着点 \(d_u\) 必须大于 \(S_{v_1} \cap S_{v_2}\) 中的所有元素。除此之外,不能和字数内的 \(S\) 相同。

于是 \(S\) 就是可能的 \(d\) 和比 \(d\) 小的所有数。

「PR #1」删数

注意到原式相当于 \(a_{i+1}-a_i = a_i - a_{i-1}\),于是考虑差分后合并两个相同的数。

设差分数组为 \(d_i\),不妨把他二进制拆分。于是问题变成了 \(d_i = 2^k\) 的情况。

\(f_i\) 表示前 \(i\) 个数的答案。设 \(g_{i,j}\) 表示以 \(i\) 为右端点合并出 \(2^j\) 时的左端点。

其中 \(g\) 的转移类似倍增。\(g_{i,j}=g_{g_{i,j-1},j-1}\),然后 \(f_i = \min \{ f_{g_{i,j}}+1 \}\)

「PR #1」守卫

在 P 国有 \(n\) 个村子,以及 \(m\) 条待修建的双向公路,第 \(i\) 条公路连接 \(u_i\)\(v_i\),修建的代价为 \(w_i\)

国王找到了 \(k\) 个守卫,每个守卫将入驻一个村子,第 \(i\) 个守卫能入驻的村子是集合 \(S_i\)

国王将派遣每个守卫去一个村子,并修建一些公路。

国王希望整个国家得到保护的同时,尽可能节省开支。因此他希望每个村子可以被恰好一个守卫经过若干条公路到达。

国王想要知道,是否存在一种修建公路和派遣守卫的方案,如果存在,修建公路的代价之和最小是多少。

对于所有数据,有 \(1 \le n \le 300, 0 \le m \le \frac{1}{2}n(n-1),1 \le w_i \le 1000\)

对于一个连通块,只能恰好有一个守卫。于是连通块和守卫间的判定可以用二分图判定。

除非无解,否则不用考虑一个连通块两个守卫的情况。

于是贪心考虑,从大到小删边。如果删掉这条边后二分图匹配不合法,意味着这条边必须保留。

「PR #2」划分

P 国的领土包含 \(N\times M\) 个城市,排成 \(N\)\(M\) 列的网格,第 \(i\) 行第 \(j\) 列的城市的坐标记为 \((i,j)\)

我们认为两个城市 \((i_1,j_1)\)\((i_2,j_2)\) 相邻当且仅当 \(|i_1−i_2|+|j_1−j_2|=1\)

国王想把城市划分为 \(K\) 个省,满足以下条件:

  • 每个城市恰好属于一个省;
  • 每个省至少包含一个城市;
  • 对于同省的两个城市,存在一条该省城市的路径以这两个城市为端点,使得路径上相邻的两个城市在网格上相邻;
  • 每个城市恰好有两个相邻的城市与其同在一个省。

请你帮助国王给出划分的一个方案,若有多种方案输出任意一种均可,若无解则输出 NO

推出每组 \((n,m,k)\) 是否有解,然后直接递归判断,能否套框框或者放若干个 \(2 \times 2\) 的矩阵。

「PR #3」最小生成树

有一张 \(n\times m\) 的网格图,第 \(x\) 行第 \(y\) 列的格点记为 \((x,y)\),给定四个单调不降数组 \(A,B,C,D\),网格图的边权由这四个数组决定,具体的:

  • \((x,y)\)\((x+1,y)\) 之间的边权为 \(A_x+B_y\)
  • \((x,y)\)\((x,y+1)\) 之间的边权为 \(C_x+D_y\)

你需要求出这张网格图最小生成树的大小。

其中,\(2 \le n,m \le 10^5\)

注意到单调性后,很自然的会把一个网格分层。

12.png

对于第 \(i\) 层的任意一条边,都会大于等于小于第 \(i\) 层的任意一条边。

于是贪心的考虑每一层选的边都尽量的多。列出式子后拆开然后前缀和和二分优化即可。

「SDOI2013」逃考

时鸽多日,终于还是把这题写了(

考虑先把每个人的监视范围。两个人范围的分界点相当于是这两个点连线的中位线。然后发现就是类似泰森多边形的东西。

那我们只要经过的这个多边形最少就可以了。可以把每个多边形看成一个点和有接壤的多边形所代表的点连边然后跑最短路。

于是考虑对每个点,把他和其他点的中位线做一个半平面交。最后队列里留下的就是这个半平面交的每个边。对于每个点都这么做一遍就可以得到这张图了。

复杂度 \(\mathcal{O}(n^2 \log n)\)

「2020-02-14 省选模拟赛」传送 (teleport)

首先可以注意到,如果所有的 \((u,v)\) 满足条件,那么所有路径也一定满足条件。

于是对于点 \(u\),只考虑他到儿子的边 \((u,v)\),于是有 \(|a_u-a_v| \le w_{u,v}\),即 \(a_v - w_{u,v} \le a_u \le a_v + w_{u,v}\)

于是对于点 \(u\) 的取值,把所有儿子的情况交起来就行了。如果存在一个 \(u\) 是空集,就无解。

对于第二问,\(x\) 的限制就是把每个区间限制加大,于是贪心考虑最小,最后答案即 \(\left\lfloor \dfrac{\max(l_i - r_i)}{2} \right\rfloor\)。如果小于 \(0\) 说明不需要扩大范围。

「2020-02-17 省选模拟赛」序列 (seq)

正难则反。因为越后的影响最大于是考虑倒着推。

考虑选出两个数 \(x,y\) 选择后删掉,这意味着在 \([x+1,y-1]\) 中的点必须先删掉。这意味着这区间一定与其他两个区间独立。同样的,对于 \([1,x-1]\)\([y+1,n]\) 也不能跨越选择。

这意味着选完两个点后,分成的区间相互独立。

所以每次第一个数只能选奇数位,第二个数是偶数位。这样才能有解。

所以对于一个区间,每次找到奇数最大值,偶数位最大值,会分成若干个区间。同时也会表示出这些点的先后关系,建出后可以跑拓扑得到答案。

快速找最大值可以 st 表。

「2020-02-25 省选模拟赛」小 B 的环 (loop)

先把原字符串倍长。

如果不考虑首位不相同的情况,意味着一个满足条件的字串不会跨越两个相邻相同的字符。利用这点把原串分成若干个块。每个块内每个字串都满足条件。

考虑首位的情况。如果对于一个 \(k\) 一定不存在,那么意味着对于 \(\forall i,s_i=s_{i+k-1}\)。这是一个 border。求出所有 border 即可。KMP。

「2020-04-03 省选模拟赛」玩具 (toy)

首先可以建出二分图,可以跑二分图最大权匹配。但是因为 KM 狗都不写所以咱写费用流。

注意到对于每个 \(k=1\),都有一个分界点,一边用这条边,另一边不用。这意味着最后答案是一个由 \(n\) 段一次函数拼出来的东西。

离线下来整体二分,利用费用流算出 \(n\) 个边界,直接计算答案即可。

「2020-04-21 省选模拟赛」树上染色 (dyeing)

首先有个显然的转移式 \(g(u)= \prod\limits_{v} (g(v)+1)\)

然后换根 DP 即可。

「2022-03-25 省选模拟赛」

一之濑帆波 (honami)

通过链的部分分发现二分和贪心是可行的。所以对于一棵树,二分一个答案,设 \(f(u)\) 表示最远没覆盖的点,\(g(u)\) 表示最近的关键点。设 \(u\) 到他父亲节点的距离为 \(faw_{u}\)

如果 \(f(u)+g(u) \le mid\) 则当前子树内全部没被覆盖点都合法。

如果 \(f(u) > mid-faw_u\),那么意味着 \(u\) 必须是关键点。

注意特判根节点。

本题卡常。把 \(f(u),g(u)\) 设成 pair 实时返回,可以解决因为不连续寻址而较慢的问题。Vx 很坏!

堀北铃音 (suzune)

不妨枚举每个数的贡献,假设当前枚举到 \(w\)。前 \(i\) 个中出现的次数为 \(s_i\)

于是区间 \([l+1,r]\) 是答案当且仅当 \(s_r - s_l > r-l-(s_r-s_l)\)。即 \(2 s_r -r > 2 s_l -l\)

对于一个 \(i\)\(v_i\) 维护 \(w\) 的个数减去不是 \(w\) 的个数。然后枚举 \(r\) 的时候计算合法 \(l\)

接下来发现这个贡献值,对于每个为 \(a_p=w\) 的位置,他们之间都是一个等差数列。

所以对于每个等差数列,每次 \(+1\) 就行。这样复杂度就下来了。

对于一段等差数列 \(y,y-1,\dots ,x\),维护他的权值 \(v_i\),接下来要对他们区间 \(+1\)。但他们之间不会有任何贡献,只要看他们与前面的等差数列算贡献就可以了。

\(t_i\) 表示权值为 \(\le i\) 的个数,也就是 \(t_i = \sum\limits_{j=1}^i c_j\)。其中 \(c_i\) 表示 \(i\)\(v\) 中的出现次数。再记 \(g_i\) 表示 \(t_i\) 的前缀和,即 \(g_i = \sum\limits_{j=1}^i t_j\)。于是这个区间的贡献即为 \(g_{y-1}-g_{x-1}\)

三个树状数组维护 \(x_i,x_i \times i,x_i \times i^2\) 来处理高维前缀即可。

少项式

写不动了(?

「2022-03-31 省选模拟赛」

BFS (bfs)

考虑 DP。重铸贪心荣光我辈义不容辞。

\(f(i)\) 表示恰好遍历前 \(i\) 个点的最小合法加边数。注意到 \(i\) 能转移到 \(j\),意味着转移后 \(i+1\)\(j\) 的层数一定不比前面的小。于是需要满足不存在边 \((u,v)\),其中 \(u \le i\)\(v > j\)

单调栈优化。且因为转移的是后缀,所以可以把后缀那块递推。

铁饭饭 (ironricerice)

考虑分块。一块大小为 \(\frac{K}{2}\)。这样一个队列里可以塞 \(2\) 个块。可以两两块之间比较。

抽象理解比较,把块与块之间连边,就是一个完全图。考虑内部点不重复的路径。而完全图的覆盖可以考虑 z 字形覆盖。也就是 \(s \rightarrow s-1 \rightarrow s+1 \rightarrow s-2 \rightarrow s+2 \dots\)。然后走 \(\frac{n}{2}\) 次。

境外势力 (covid)

鸽。

「2022-04-03 联考」

基础莫比乌斯反演练习题 (array)

不妨设 \(f(i)\) 表示 \(\gcd = i\) 的乘积和,于是答案是 \(\sum\limits_{i=1}^q f(i)\)

\(F(i)\) 表示 \(\gcd = i\) 的倍数的成绩和,于是有 \(F(i) = \sum\limits_{i|j} f(j)\)。容斥 \(f(i)=F(i)-\sum\limits_{j=2}^{\left\lfloor \frac{m}{i} \right\rfloor} f(ij)\)。可以筛。

如果不考虑 \(\operatorname{lcm}\) 的限制,于是 \(F(i) = \left( \dfrac{ (\left\lfloor \frac{m}{i} \right\rfloor i + i) \times \left\lfloor \frac{m}{i} \right\rfloor }{2} \right)\)

再设 \(g(i)\) 表示 \(\operatorname{lcm} = i\) 的答案和。于是

\[F(i) = \left( \dfrac{ (\left\lfloor \frac{m}{i} \right\rfloor i + i) \times \left\lfloor \frac{m}{i} \right\rfloor }{2} \right) - i^n \sum\limits_{j=1}^{\left\lfloor \frac{p-1}{i} \right\rfloor} g(j) \]

于是对 \(g\) 做个前缀和就可以快速算 \(F\)

\(G(i)\) 表示 \(\operatorname{lcm} = i\) 的因数的乘积和。于是有 \(G(i) = d(i)^n\),其中 \(d(i)\) 表示因数和。

因为有 \(G(i) = \sum\limits_{j | i} g(j)\),所以有 \(g(i) = G(i) - \sum\limits_{j|i,j \neq i} G(j)\)。可以筛。

基础线性基练习题 (set)

考虑计算每个数贡献的次数。

于是对于一个数 \(x\),如果他不能被别的数异或表示,则没有贡献。

提出这些数,得到一个极大无关组 \(A\),然后对于剩下的数再取一个极大无关组 \(B\)

枚举 \(A\),假设当前为 \(x\),把除了 \(x\) 的加入 \(B\),再得到一个极大的无关组 \(C\)

此时如果 \(\operatorname{R}(A) = \operatorname{R}(C)\),则 \(x\) 可以被表示。否则如果大于,则 \(x\) 没有贡献。

把没有贡献的 \(x\) 删掉后,设剩下的数集合是 \(S\),则答案为 \(|S| 2^{|S|-\operatorname{R}(S)}-1\)

基础斯坦纳树练习题 (tree)

发现如果出现重边一定会有更优的方案。于是设 \(d(x,y)\) 表示距离。相当于求一个 \(x\),使 \(d(x,a_i)+d(x,b_j)+d(x,k)\) 最小。

注意 \(|A|,|B|\) 很小,所以先对于 \(A,B\) 中的所有点跑出他的单源最短路。

接着枚举 \(A,B\),只要求出对于每个点的最短路就可以了。于是对于每个 \(x\),设他初始的 \(d\)\(d(x,a_i)+d(x,b_j)\)。然后跑 dijkstra,这样每个点最后的结果就是答案。

但是多一个 \(\log\),考虑不用堆优化,用桶优化即可。

「2022-04-06 省选模拟赛」

传教 (mission)

发现题目那样等价设 \(c_i = a_i \oplus b_i\),然后让 \(c\)\(0\) 就好了。

首先贪心是 \(n^2\),没有 \(\log\),让我看看是谁被部分分误导把贪心过程二进制拆分然后逐个做的。哦是我的那没事了(

注意到,发现题目的修改,对膜 \(k\) 相同的数,每组是不干扰的。维护异或前缀和和结尾判断不为 \(0\) 的个数。

根据 \(k\) 分块。若 \(k > \sqrt{n}\),暴力算;若 \(k \le \sqrt{n}\),每组分块维护。

方程 (equation)

首先 \(t\) 没啥大用,塞进一个 set 就行了。考虑把剩下式子拆开,发现得到

\[\dfrac{(a+b)^2-c^2}{(a+b)c} - \dfrac{(a+b)^2+(a+b)c+c^2}{c^2} \equiv t \pmod{p} \]

\(x=a+b\),于是原方程变成 \(x\)\(c\) 的方程。

于是可以用 NTT 求出 \(a+b \equiv i \pmod{p}\) 的方案数,设结果为 \(\sum v_i [x^i]\)

回到原方程,注意到如果 \((x,c)\) 是解,那么 \((kx,kc)\) 也是一个解。所以求出 \(x=1\) 就可以求出所有解了。

考虑算出 \(p\) 的原根 \(g\),这样 \(kx\) 可以表示为 \(g^u \times g^v\),所以以原根的次数 \(g^u=v\) 作为多项式的次数 \([x^u]\)。卷完就可以算出 \(k=i\) 时的答案。

没写。(理不直气也壮。

「2022-04-10 联考」

石仔放置 (set)

把棋盘划分成若干个 \(2 \times 2\) 的子矩形。如果一个子矩形左上被禁了,意味着只能放右下。但这也意味着之后这部分右下的子矩阵也只能放右下。

建一颗线段树,维护每一行的子矩形是否存在两个子矩形不合法。维护被禁止的左上纵坐标最小值,右下纵坐标最大值。这个单行的答案是否存在不合法就是 \(\max \ge \min\)

上传标记时,如果已经不合法就是不合法,否则应该有 \(\max(mid+1,r) \ge \min(l,mid)\)

当行的 \(\min,\max\) 可以用 set 实时维护。


剩下两组合题先放着(?)。

「2022-04-17 联考」

排队做操 (queue)

是谁一直想组合方法?是我啊那没事了(

不妨设 \(f(i,j)\) 表示考虑到第 \(i\) 个,至多有 \(j\) 个刺头的方案数。答案就是差分一下。有转移:

\[f(i,j) = 2j \cdot (f(i-1,j) - f(i-1,j-1)) + i \cdot f(i-1,j-1) \]

考虑矩阵转移。但矩阵和 \(i\) 有关。模数 \(p\) 很小,转移每 \(p\) 个一个循环,于是预处理出 \(p\) 个转移矩阵。然后就可以快速算了。

昵称 (nickname)

数位 DP。设 \(f(i,j)\) 剩下 \(i\) 个数字,匹配到了给定的第 \(j\) 位。但每次失配后回到原处太慢了,考虑 KMP。于是设 \(t(i,j)\) 表示匹配到第 \(i\) 个,下一个数字是 \(j\),KMP 能转移到的位置。

于是方程 \(f(i,j) = \sum\limits_{i=0}^9 f(i-1,t(j,k))\)

帝国防卫 (empire)

首先发现这个修改层数是 \(\log\) 级别的,于是可以暴力跳层。注意到修改是对深度相同的一段区间修改,于是考虑对 bfs 序建出一颗线段树。每个点初始点权为 \(c_i\),每次减少若干个数,问什么时候 \(\le 0\)

这颗线段树上套一个线段树,用来计算在这段区间内小于当前修改的 \(x\) 的值,这里可以线段树二分。如果打 \(\le 0\) 的就打个标记,且一个点最多被打一次标记。所以可以暴力打标记。

考虑查询的时候是查询子树和。可以通过对点打标记的形式然后用树状数组维护。

复杂度 \(\mathcal{O}(n \log{a_i} \log^2 n)\)

考虑欺骗出题人。 把全部问题离线,整体二分计算出一个时刻,会被打上标记的点。

复杂度 \(\mathcal{O} (n \log_{a_i} \log^2 n )\)

posted @ 2022-04-30 13:57  Rainy7  阅读(397)  评论(2编辑  收藏  举报