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 imes 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 imes n)的方阵的方案数(g_n),由于(n)必然为偶数,于是可以考虑其为(3 imes (n imes 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})对(kin N)均成立,故此时一定可行。(n)为(>1)的奇数时,我们可以先拿(3)个奇数出来选(2^0,2^2,2^4),剩下的数再和(n)为偶数的方案一样选即可。注意到此时我们需要两个(0)给(2^1)和(2^3),那么当前区间不合法的条件就很明显了:
-
(n=1)
-
(n=2k+1,m<2(kin N_{+}))
注意到两个条件是或的关系,于是我们可以强制第一个条件满足(mgeq 2).
考虑用线段树维护这个东西,记(dl/r[i][j])表示子区间包含当前区间左/右端点,且子区间的(0)有(i)个,子区间内(1)的个数(mod 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 iin[l,r]),它的影响是(frac{(i-l+1)(i-l+2)}{2}v); 而对(forall iin(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.egin{bmatrix} a & 0 & cdots & 0 & b\ c & 0 & cdots & 0 & d \ end{bmatrix})
(2.egin{bmatrix} a & 0 & cdots & 0 & b\ b & 0 & cdots & 0 & d \ end{bmatrix})
(egin{bmatrix} a & 0 & cdots & 0 & c\ c & 0 & cdots & 0 & d \ end{bmatrix})(两者等价)
(3.egin{bmatrix} a & 0 & cdots & 0 & a\ c & 0 & cdots & 0 & d \ end{bmatrix})
(egin{bmatrix} a & 0 & cdots & 0 & b\ c & 0 & cdots & 0 & c \ end{bmatrix})(两者等价)
(4.egin{bmatrix} a & 0 & cdots & 0 & a\ b & 0 & cdots & 0 & b \ end{bmatrix})
(5.egin{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),所以(qgeq lfloorfrac{n}{p+1} floor),合法性得证
联合省选2020
以下按照个人认为的难度顺序排序
Day1
loj#3305. 「联合省选 2020 B」卡牌游戏
记(s_i=sum_{j=1}^i a_j),由于每个(s_i)至多产生1次贡献,故答案(=sum_{i=2}^nmax(s_i,0)).
loj#3306. 「联合省选 2020 B」消息传递
建出点分树,对每个点记录下它在点分树上的祖先到这个点的距离(这个可以在建立点分树的时候通过dfs当前分治重心所管理的子树得到),同时在点分树上对每个点维护其子树中的点到这个点的距离的桶。询问时直接在点分树上暴力跳父亲,然后对着桶查一下即可。
loj#3300. 「联合省选 2020 A」组合数问题
主要思路是将后面的(sum x^kdbinom{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}),那么在(iin[1,j-1])时,(min(S_{0i},S_{1i})=S_{0i}),此时(j-1)是最优解。在(iin[j,n])时,(min(S_{0i},S_{1i})=S_{1i}),为了让这个值最大,需要找到一个最大的(p)使(S_{1p}=S_{1j}).
这两个操作都可以在线段树上二分实现,时间复杂度为(O(nlog n))