一些省选题
BJOI2019
loj #3089. 「BJOI2019」奥术神杖
看见乘法的贡献就应该考虑取对数,之后变成\(\frac{1}{c}\sum \ln v_i\).
求这个式子的最值可以考虑分数规划,即二分\(mid\)后check\(\frac{1}{c}\sum \ln v_i>mid\)
整理后得\(\sum(\ln v_i-mid)>0\),故可以将每个串的长度记作\(\ln v_i-mid\),之后就是一个经典的在AC自动机上dp的过程了,注意记录转移以输出方案。
loj #3090. 「BJOI2019」勘破神机
先考虑\(m=2\)的case,发现填满一个\(2\times n\)的方格的方案就是\(fib_{n+1}\),其中\(fib_i\)表示斐波那契数列的第\(i\)项。
答案\(=\frac{1}{r-l+1}\sum_{i=l+1}^{r+1}\dbinom{fib_i}{k}\),和这个题是一样的。
接下来考虑\(m=3\)的case。依然是先算填满一个\(3\times n\)的方阵的方案数\(g_n\),由于\(n\)必然为偶数,于是可以考虑其为\(3\times (n\times 2)\)的方案数。递推的话可以考虑上一个不经过分界线的矩阵大小,若其为\(2\)则有\(3\)种,否则则为\(2\)种。故可得到递推式\(g_n=\sum_{i=1}^{n-2}2g_i+3g_{n-1}\).将\(g_{n+1}\)与\(g_n\)做差可得\(g_{n+1}=4g_n-g_{n-1}\),边界条件\(g_0=1,g_1=3\).利用特征根法解得通项式如下:
剩下的和\(m=2\)的一致。
loj #3092. 「BJOI2019」排兵布阵
分组背包即可,跑得飞快。
loj #3093. 「BJOI2019」光线
记\(f_i\)为1号镜子入射的光线从\(i\)号镜子向下射出的量,\(g_i\)表示1号镜子入射的光线从\(i\)号镜子向上反射的量,转移有:
注意由于\(g_{n+1}=0\),所以有\(f_n=a_nf_{n-1},g_n=b_nf_{n-1}\).
令\(X_i=\frac{f_i}{f_{i-1}},Y_i=\frac{g_i}{f_{i-1}}\),那么转移式可以写成:
由于\(X_n,Y_n\)已知,所以可以倒推求出\(X_i\),再求出\(f_n\)即可。
当然还有一个做法是不显式的设出\(X,Y\),注意到由于\(f_n,g_n\)分别可以被\(f_{n-1},g_{n-1}\)表示出来,再往前推既可以发现\(f_i,g_i\)分别可以被\(f_{i-1},g_{i-1}\)表示。最后由\(f_0=1\)再往后乘一遍系数即可。
loj #3094. 「BJOI2019」删数
对于一个序列\(a\)首先考虑怎样才能使它被一次删干净。由于长度为\(n\),所以\(a\)中必有元素\(n\),假设有\(k_1\)个。为了能继续删,序列\(a\)中必有元素\(n-k_1\),假设有\(k_2\)个,以此类推。
用一个形象化的比喻来解释最后的结论:记\(b_i=\sum_{j=1}^n [a_j=i]\),考虑一根数轴上有一些柱子,点\(i\)的柱子高度为\(b_i\),那么最少修改次数等于将\([1,n]\)中的所有柱子向右推倒后未被覆盖的整点个数。
考虑用线段树维护这个过程,每个节点维护当前区间的最小值,最小值出现次数和答案,只有在最小值为0时它的次数才会被记入答案中。对于修改,单点修改直接做,整体加减的话可以记录原点\(0\)的位置,每次直接移动\(0\)的位置,再修改由此离开或进入\([1,n]\)的柱子的贡献,此时需要将下标整体加上一个较大的数。
BJOI2018
loj #2491. 「BJOI2018」求和
注意到\(k\)很小,于是可以对所有\(k\)预处理出每个点深度的\(k\)次幂,再用树链剖分查询即可。
loj #2492. 「BJOI2018」二进制
结论五分钟,实现两小时
假设某个区间有\(m\)个\(0\)和\(n\)个\(1\),那么问题等价于从集合\(\{2^0,2^1,\cdots,2^{n+m-1}\}\)中选出\(n\)个数使其和为3的倍数。
\(n=1\)时显然不成立。\(n\)为偶数时注意到\(3|2^{2k}+2^{2k+1}\)对\(k\in N\)均成立,故此时一定可行。\(n\)为\(>1\)的奇数时,我们可以先拿\(3\)个奇数出来选\(2^0,2^2,2^4\),剩下的数再和\(n\)为偶数的方案一样选即可。注意到此时我们需要两个\(0\)给\(2^1\)和\(2^3\),那么当前区间不合法的条件就很明显了:
-
\(n=1\)
-
\(n=2k+1,m<2(k\in N_{+})\)
注意到两个条件是或的关系,于是我们可以强制第一个条件满足\(m\geq 2\).
考虑用线段树维护这个东西,记\(dl/r[i][j]\)表示子区间包含当前区间左/右端点,且子区间的\(0\)有\(i\)个,子区间内\(1\)的个数\(\bmod\ 2\)为\(j\)的子区间数量(它被用来统计第二个条件的贡献)。\(fl/r[i][j]\)表示子区间包含当前区间的左/右端点,且子区间内有\(0/1/\geq 2\)个\(0\),\(1\)个1的子区间数(用来处理第一个条件的贡献),\(c0/c1\)表示区间内\(0/1\)的个数,\(l0/r0\)表示从左端点/右端点出发的极长\(0\)段的长度(这两个是方便维护\(dl/r,fl/r\)的)。具体的pushup由于细节繁多建议直接看代码。
loj #2512. 「BJOI2018」链上二次求和
记\(s_i\)为\(a_i\)的前缀和,\(ss_i\)为\(s_i\)的前缀和。二次求和肯定要写两次前缀和啊
对于一个询问\([l,r]\),把它的答案写出来:
考虑如何动态维护\(ss_i\),这样的话对每次询问可以直接查\([1,n],[l-1,r-1],[n-r,n-l]\),然后减一减得到答案。
对于一个修改\((l,r,v)\),对\(\forall i\in[l,r]\),它的影响是\(\frac{(i-l+1)(i-l+2)}{2}v\); 而对\(\forall i\in(r,n]\),记\(len=r-l+1\),则贡献为\((\frac{len(len+1)}{2}+len(i-r))v\).
注意到上面的所有贡献都可以看成是关于\(i\)的二次函数,于是可以在build的时候预处理出\(i^0,i^1,i^2\),每次修改直接传入各次项前的系数即可。具体实现可参考代码。
loj #2513. 「BJOI2018」治疗之雨
连续两年高妙消元?
记\(f_i\)表示当前血量为\(i\),变成\(0\)的期望次数。则有:
其中\(A_{i,j}\)为血量由\(i\)变为\(j\)的概率,经过简单的分类讨论可以得到
其中\(B_i\)表示在\(k\)次操作中恰好选到某个特定点\(i\)次的概率,则有:
对\(f\),由于\(i\)可能由比它大的数转移过来,所以我们需要高斯消元,但是显然时间限制不允许我们这么做。
将\(f_i\)的转移变形后得到:
于是\(f_i\)可以由\(f_{i-1}\)得到,我们将\(f_1\)看做主元,可以表示出\(f_{2...n}\).
但是对\(f_n\)的转移,由于不存在\(f_{n+1}\)所以上面的变形不成立,但是我们直接利用这个转移建立起\(f_n\)与\(f_1\)的第二个等量关系,之后解方程得到\(f_1\)。注意特判一下\(m=0\)或\(k=0\)的情况。
SDOI2019
loj #3110. 「SDOI2019」快速查询
维护一些全局tag:加法add,乘法mul,赋值all以及最近的一次全局赋值时间lstall. 再对有单点赋值的位置记录一下上一次赋的值和时间。单点询问的时候比较一下全局时间和单点时间的先后。询问和的话在修改的时候顺便维护一下即可。
loj #3111. 「SDOI2019」染色
一眼有一个没分的dp思路:记\(f_{i,j,k}\)表示前\(i\)列已经填完,第\(i\)列的颜色为\(j,k\)的方案数。
考虑压缩状态,记\(g_{i,j}\)表示前\(i\)列,第\(i\)列新填的颜色是\(j\)的方案数。当第\(i\)列被填满时,考虑记录下面位置的颜色。那么问题变成出列一列都没有颜色的情况。注意到我们可以将这样的连续的几列放在一起处理,并且这些列的情况只与开头和结尾的两个非全零列有关,大致有以下几种:
\(1.\begin{bmatrix} a & 0 & \cdots & 0 & b\\ c & 0 & \cdots & 0 & d \\ \end{bmatrix}\)
\(2.\begin{bmatrix} a & 0 & \cdots & 0 & b\\ b & 0 & \cdots & 0 & d \\ \end{bmatrix}\)
\(\begin{bmatrix} a & 0 & \cdots & 0 & c\\ c & 0 & \cdots & 0 & d \\ \end{bmatrix}\)(两者等价)
\(3.\begin{bmatrix} a & 0 & \cdots & 0 & a\\ c & 0 & \cdots & 0 & d \\ \end{bmatrix}\)
\(\begin{bmatrix} a & 0 & \cdots & 0 & b\\ c & 0 & \cdots & 0 & c \\ \end{bmatrix}\)(两者等价)
\(4.\begin{bmatrix} a & 0 & \cdots & 0 & a\\ b & 0 & \cdots & 0 & b \\ \end{bmatrix}\)
\(5.\begin{bmatrix} a & 0 & \cdots & 0 & b\\ b & 0 & \cdots & 0 & a \\ \end{bmatrix}\)
记\(f_{i,j}\)表示有\(i\)列\(0\),其中首尾两列的情况为\(j\)的方案数(注意这个状态中我们只确定了首尾两列的相等情况,而没有确定具体的数是什么)
预处理出\(f\),之后对每一对极长连续的全零列转移,暴力\(O(nc)\)的转移可以得到96pts. 代码有亿点细节。
写完96pts的代码后发现我们每次对\(g\)的操作和上一题是相同的,于是可以把前一题的代码蒯过来再改一下。这里笔者由于笔者比较懒只有96pts的代码。
loj #3112. 「SDOI2019」世界地图
对于询问\([l,r]\),考虑将\([1,l-1]\)与\([r+1,n]\)的MST合并.即需要预处理所有前缀和后缀的MST。
这里只考虑前缀的MST,后缀的是类似情况。一个比较显然的思路是由\([1,l-1]\)推出\([1,l]\)。考虑一条新的边\((u,v,w)\)在何时会替代原MST中的边:在原MST中\(u,v\)连通且两点间路径的最大权值\(>w\).
记\([1.l]\)中第一列点和最后一列点为关键点,\(pre_l\)为随着\(l\)的增大可能会被删去的边,根据kruskal的过程不难发现加入边\((u,v)\)等价于将它们的祖先连起来,所以\(pre_l\)的边的端点可以看成是关键点。所以每次向后拓展时只需要考虑\(pre_l\)与新加的边。
再考虑合并,发现我们依然可以只关注关键点的连边,于是可以将\(pre_{l-1}\)和\(suf_{r+1}\)如上面一样的合并起来,具体合并过程可见代码。
loj #3113. 「SDOI2019」热闹的聚会与尴尬的聚会
注意到第二问这个求独立集是个经典的NPC问题,所以一个直观的想法是让\(q\)尽量小,也就是要让\(p\)尽量大。
那么有一个这样的贪心思路:每次删去当前图中度数最小的点(记作这一次删除的源点),并删去其相邻的点。每次删点时删去的点的度数最大值即为\(p\),所有删去的点在一起则构成第二问的独立集。
考虑这样得到的独立集的大小,由于每个被删去的源点在被删去时的度数\(\leq p\),所以每次删去的点的总数\(\leq p+1\),所以\(q\geq \lfloor\frac{n}{p+1}\rfloor\),合法性得证
联合省选2020
以下按照个人认为的难度顺序排序
Day1
loj#3305. 「联合省选 2020 B」卡牌游戏
记\(s_i=\sum_{j=1}^i a_j\),由于每个\(s_i\)至多产生1次贡献,故答案\(=\sum_{i=2}^n\max(s_i,0)\).
loj#3306. 「联合省选 2020 B」消息传递
建出点分树,对每个点记录下它在点分树上的祖先到这个点的距离(这个可以在建立点分树的时候通过dfs当前分治重心所管理的子树得到),同时在点分树上对每个点维护其子树中的点到这个点的距离的桶。询问时直接在点分树上暴力跳父亲,然后对着桶查一下即可。
loj#3300. 「联合省选 2020 A」组合数问题
主要思路是将后面的\(\sum x^k\dbinom{n}{k}\)分离出来,再用二项式定理合起来即可。
其中\(S(i,j)\)表示第二类斯特林数。
预处理一堆东西之后就可以\(O(m^2)\)了。
loj#3299. 「联合省选 2020 A | B」冰火战士
记冰系战士和火系战士在温度\(i\)时上场战士的能量和分别为\(S_{0i},S_{1i}\),那么问题就是求最大的\(i\)使\(\min(S_{0i},S_{1i})\)的最大。
记\(j\)为最小的\(i\)使\(S_{0i}> S_{1i}\),那么在\(i\in[1,j-1]\)时,\(\min(S_{0i},S_{1i})=S_{0i}\),此时\(j-1\)是最优解。在\(i\in[j,n]\)时,\(\min(S_{0i},S_{1i})=S_{1i}\),为了让这个值最大,需要找到一个最大的\(p\)使\(S_{1p}=S_{1j}\).
这两个操作都可以在线段树上二分实现,时间复杂度为\(O(n\log n)\)