因为一道一道写太浪费时间了所以干脆直接写一起好了……代码的话为了节省空间自己上(OJ)上看吧
loj#2347. 「JOI 2018 Final」寒冬暖炉
来搞笑的
相当于一条线段上选出(k)段,等价于断开(k-1)段,(sort)一下取最大的(k-1)个即可
loj#2348. 「JOI 2018 Final」美术展览
按(A)排个序然后枚举最小值,相当于要求出右边最大的(S-A),两个(S-A)的大小关系等价于前缀和(-A)的大小关系,从后往前(O(n))递推就行了
loj#6495. 「雅礼集训 2018 Day1」树
设(f_{i,j})表示(i)个点高度为(j)的方案数,因为(2)号点的父亲只能是(1),我们可以把它看做特殊的。那么转移就是
柿子的意思就是,我们枚举以(2)号点为根的子树的高度,如果小于(j-1)那么剩下的高度必须等于(j),否则剩下部分高度任意
听说这个方法吊打(std)
loj#2520. 「FJOI2018」所罗门王的宝藏
对于同一行的所有数字来说,可以看做可以看做那几列的次数有特定的关系,可以在它们中间连,边权为对应关系大小((n)个点连(n-1)条边就行了)。然后对每一个联通块随便从哪个点开始跑(bfs)求出到所有点的距离。如果有一条边满足(dis_u+w eq dis_v)就说明无解
loj#2521. 「FJOI2018」领导集团问题
都看出数组的特性了还没想明白怎么做……我可能脑子被吃了……
首先每个选出的点都得大于等于它的祖先,这样的话不一定是一个联通块。我们可以把它变成一个联通块,然后修改那些不满足条件的节点的值,易证方案一定存在。设(f_{i,j})表示考虑到(i)这棵子树,(i)的权值被改为(j),那么选出的联通块中最多有多少个点能够不修改权值
如果我们把(f)数组从后往前差分一下,那么只要能够维护这个差分数组我们就可以维护答案了
对于(f)数组的转移来说,节点(v)的权值必须小于节点(u),就是(f_{u,i}+=f_{v,k}(ileq k)),也就是把(f_v)后缀(max)一下再给(f_u)按位相加
易知(f_v)一定是一个非升的,所以后缀(max)数组就是原数组
然而加上(f_u)之后它可能就不一定是一个非升的了。我们先把所有的(f_v)合并起来,此时(f_u)的值就是初始的值,即只有(f_{u,a_u})为(1)其它都为(0),它的后缀差分数组一定是一个(-1)和一个(1)邻着其它都为(0)。那么加上(f_u)之后的新数组最多只会有一个位置的后缀差分位置发生变化,相当于只要找到前驱然后更改就行了。(map)加启发式合并即可
loj#6513. 「雅礼集训 2018 Day10」足球大战
记(p_i,q_i)分别表示(a,b)赢(i)局的概率,如(p_i={nchoose i}p^i(1-p)^{n-i}),(q_i)同理,那么把(b_i)做个前缀和,每个(a_i)乘上(b_{i-1})加起来就好了。因为空间限制比较小(p,q)都不用存了
loj#6515. 「雅礼集训 2018 Day10」贪玩蓝月
模拟赛考过。区间查询最大值有线段树和(ST)表,线段树复杂度太大了所以用(ST)表。维护两个序列一个从前往后一个从后往前。一旦一个空了就直接暴力重构,把其中一半扔到另一边,易知每个物品只会被重构(O(log n))次(虽然我觉得复杂度可能是线性的)
loj#6514. 「雅礼集训 2018 Day10」文明
设(1)号点为(rt),我们分两种情况考虑,一种是(a_i)在(rt)的子树内,一种是(a_i)在(rt)的子树外,并记(res)表示没有被(1)号点占领的点的总数
首先不难看出,如果(a_i)和(rt)中间隔着(d)个点,那么(a_i)能占领的是其中的(leftlfloorfrac{d}{2} ight floor)个点
先考虑所有在(rt)的子树内的点,对于一个点(a_i),我们倍增让它跳到它能占领的深度最小的点(p_i),那么(p_i)以及它的子树都会变得不可选,于是(res+=size_{p_i})
然而会有一个问题,比方说(p_j)在(p_i)的子树中,然而按上面的方法的话(p_j)的子树被统计了两次,显然不行
那么我们把所有的(p_i)按照欧拉序排序,那么(p_i)的子树中的点一定在(p_i)之后的一段连续的区间里,我们用一个指针扫一下,只加上(p_i)的贡献,然后令(i)跳过这段区间就行了
接下来的问题就是(a_i)在(rt)子树之外的情况。此时如果(p_i)不在(rt)到根节点的路径上,那么被删除的依然是一棵子树,按照(a_i)在(rt)子树内的方法做就行了
如果(p_i)在(rt)到根节点的路径上,我们记(v)表示(rt)能占领的最后一个点,也就是(p_i)到(rt)的路径上的第一个点,那么(res+=n-size_v)。并且我们发现,我们只要记录下深度最深的一个(v),并计算它的贡献就行了
顺带一提,对于那些(p_i)不在(rt)到根节点路径上的点,显然只有当(dep_{LCA(rt,a_i)}geq dep_v)时才会有贡献
loj#6507. 「雅礼集训 2018 Day7」A
如果一次操作对某个区间的影响是一样的(即最小值还是那个数),那么我们直接打标记退出;若一次操作对某个区间无影响就直接退出
然后就过了
证明我不会
loj#2349. 「JOI 2018 Final」团子制作
如果我们看成红(1)绿(2)白(3),每一次在绿的地方统计,那么会发现只有在同一条对角线上的绿色的团子会互相影响。那么记一个状态表示上一个团子是不放横放还是竖放就行了
loj#2350. 「JOI 2018 Final」月票购买
如果最短路和免费路径没有交那么答案就是直接跑一遍最短路,所以我们假设最短路和免费路径有交。易知最短路和免费路径的交一定是连续一段,否则可以一直从交里第一段跑到最后一段。设(A,B)为免费路径上某两点,那么最短路应该是形如(u->A->B->v)的形式,其中(A->B)这一段免费。那么这种情况下一定存在一条边满足它连接的两条边中一个点不经过免费路径上的边直接到达(u),另一个点经过一段免费路径上的边到达(v)((u,v)也可以反过来)。我们最主要的是保证免费路径这一段必须事合法的。那么我们按(ST)之间最短路的图递推,维护一下经过一段免费路径到达(u)和(v)的值就好了
不清楚的话建议看代码,代码应该比较明了
loj#2351. 「JOI 2018 Final」毒蛇越狱
我好像连高维前缀和是啥都给忘了……我们记一个(f_S)和(g_S)分别表示只有(S)的子集为(1)的总贡献和至少有(S)全为(1)的贡献。对于通配符直接处理就行了。然而这样有可能会让某些规定为(0)的项为(1),那么容斥。比方说我们设(x)是强制为(1)的位置的集合,(z)是通配符所在位置的集合。首先(z)全都随便选,总的贡献就是(x)中随便选减去(x)中至少一个不选加上至少两个不选……容斥下去就行了。然而这样的话单次复杂度是(O(2^{L})),其中(L)表示(1)的个数。我们发现(0,1,?)三种字符中出现次数最少的不会超过(6),那么我们就用出现次数最少的来容斥就行了。如果是通配符出现次数最少直接把对应的答案加起来就行了。复杂度为(O(2^{L}+2^6q))
loj#3010. 「JOI 2019 Final」勇者比太郎
如果一个位置为(J),那么满足条件的四元组个数就是它右边的(O)个数乘上它下面的(I)个数,模拟一下就好了
loj#3011. 「JOI 2019 Final」画展
把画框按大小升序排序,画按价值为第一关键字大小为第二关键字升序排序,那么只要画框和画都从右往左考虑肯定合法,而且画框肯定是从右往左考虑最优。对于画(i)来说,如果某个画框(j)被占了一副画,那么它的美观度大于(i),而且因为它能放进画框所以哪怕(i)替换它也不会更优。那么我们只要维护两个指针一个表示画框,一个表示画,每一次画可以加入画框就加入并(++ans)即可
loj#3012. 「JOI 2019 Final」有趣的家庭菜园 3
我讨厌(dp)……永远做不来……设(f_{i,j,k,0/1/2})表示前(i)个数中有(j)个红色,(k)个绿色,(i-j-k)个黄色,结尾为红/绿/黄的最小代价。因为只能对换而且代价最小,所以相同颜色之间的相对顺序肯定不变。如果已经确定了(i,j,k),下一个比方说要一个红色,那么我们找到第(j+1)个红色的位置(p),并算一下(p-1)中红,绿,黄的个数分别减(j,k,i-j-k)的值,即为真正要对换的次数。转移就行了
洛谷P4437 [HNOI/AHOI2018]排列
不难发现(a_i)代表的是(a_i)这个点必须要排在(i)的前面,那么我们可以从(a_i)到(i)连一条边,一个合法的排序就是这个图的一个拓扑序
假设现在有两段,一段为(A),所有数的(w)之和为(w_A),有(n)个数,一段为(B),总和(w_B),有(m)个数。把(A)放前(B)放后和把(B)放前(A)放后的方案中,总的贡献里不同的只有一项,而这项里前者为(w_A imes m),后者为(w_B imes n),也就是说,当(w_A imes m<w_B imes n),即({w_Aover n}<{w_Bover m})的时候(A)放前面更优。也就是说两端相同的我们按平均数的大小的来选择
我们枚举值最小的(i),如果它没有父亲直接选它,如果有父亲那么选完父亲之后肯定第一个选它,也就是说它其实是可以看做是和父亲在同一个区间里的,那么只要在枚举到的时候加上它的贡献,然后把它合并到父亲上就行了
洛谷P4425 [HNOI/AHOI2018]转盘
看(Kelin)大佬的吧它写的挺好的
洛谷P4426 [HNOI/AHOI2018]毒瘤
考虑到非树边很少我们可以枚举状态,我们只要对于每条非树边枚举上面的点选不选就可以做到(O(n2^s))的复杂度,其中(s)为非树边条数,最大为(11)
我们发现如果直接暴力树形(dp)有很多重复状态,我们对所有的(22)个关键点建出虚树,对于其中一条边的转移可以写成
而且所有的系数都是不变的
那么我们可以预处理出所有系数,那么枚举的时候每一次的复杂度就是(O(s))了,总复杂度为(O(n+s2^s))
loj#3013. 「JOI 2019 Final」硬币收藏
首先移硬币和移空格是等价的,对于叠在一起的硬币移每一个都是等价的,每个硬币进入区域的时候肯定是进离它最近的那个。那么我们开个桶,初始全为(-1),然后进一个硬币就(++),然后枚举列,从左到右,如果当前列可以放,那么就放进去,否则累计到下一列,并把当前所有硬币次数(++)
loj#2977. 「THUSCH 2017」巧克力
话说斯坦纳树是个啥……
首先我们二分中位数,所有小于中位数的权值设为(999),大于中位数的设为(1001),那么只要在满足联通和颜色的条件下取最小代价就做到了个数为第一关键字,中位数为第二关键字,而且(最小值+1)/2就是个数,如果最小值小于等于个数乘1000则当前答案可行。然后求最小值的话就是斯……斯坦纳树……我们把每一种颜色随机到(0)到(k)以内,然后每次斯坦纳树求最小代价
loj#2491. 「BJOI2018」求和
预处理一下前缀(k)次和就好了,连插值都不用
CF1138A. Sushi for Two
把所有长度相同的缩成一个点,两两相邻的更新答案就行了
CF1138B. Circus
记第二个为(1)的数总共(len)个,设选(x)个(11),(y)个(10)或(01),(z)个(00),选(11)等价于(len-=2),选(01)或(10)等价于(len-=1),选(00),无影响,也就是要满足(2x+y=len)且(x+y+z=n/2),枚举一下(x,y)就行了
CF1138C. Skyscrapers
对于每行(sort)一下并离散,记录一下该位置离散后的值和该行的最大值。列同理。那么每个位置实际的值就是行和列中离散之后较大的那个值,再把对应的行和列最大值改一改就行了
CF1138D. Camp Schedule
不难发现要让(t)出现最多,一开始直接一个一个搞出整个串,之后按(kmp)来就行了
CF1138E. Museums Tour
分层图+强连通分量缩点。首先把点按时间拆开,然后缩点,易证原图中的一个强连通分量中,如果两个时间不在新图的同一个强连通分量中,那么两个时间代表的强连通分量之间不会有边相连。在(DAG)上(dp)就行了(注意千万不要把不能到达的点统计进答案!)(顺便注意卡一下空间)
loj#2561. 「SDOI2018」物理实验
计算几何怎么比多项式还难调……
首先你要会坐标系的平移和旋转,这个不讲了,不会的看视频去
我们可以把每条线段投影到坐标轴上,那么单位线段的长度就是这条线段和直线夹角的(sec)值(就是(cos)的倒数)
因为线段互不相交,我们可以切一条线过去与这些线段相交,这些交点位置会变,但是相对顺序是不变的,所以我们可以用一个平衡树来维护
首先最优解肯定有一端和一条线段有同一个端点,证明的话很简单,假设两端都不在线段的端点上,那么我们肯定可以向更优的一边平移,答案不会变劣
那么我们只要维护一下前缀和然后枚举右端点,暴力计算最长距离,同理也可以枚举左端点
然而因为维护了前缀和会导致精度爆炸,所以我们可以用一个双指针维护这条长为(L)的线段的左右端点,然后维护一下离左端点最近的线段端点和离右端点最近的线段端点,看一下哪个更近,移动了(x)之后就要减去(l)段(x)的贡献,加上(r)段(x)的贡献
还有,别写可删堆,会因为一些莫名其妙的原因挂掉
loj#2565. 「SDOI2018」旧试题
大……大毒瘤……
一起去膜拜(shadowice)吧
洛谷P4320 道路相遇
建出广义圆方树,那么路上必经的点数就是路上的圆点个数,圆点个数就等于边数除以(2)加一
loj#2566. 「SDOI2018」荣誉称号
和上面那题一样只不过改成(k)个点了,这种情况下数点很容易重复,我们数边。把每个圆点的权值记为(1),并赋值到它父亲的那条边去,然后把所有的关键点按欧拉序排序,每一次查询相邻两个点之间的路径的边权和,那么这个联通块中每一条边都会被统计到恰好两次,除以二之后再减去关键点的数量就行了。顺便我们并没有记整个联通块的(LCA)的贡献,记得加上
loj#2562. 「SDOI2018」战略游戏
对于一个点来说,它除以二向下取整可以看做它在完全二叉树上的父亲,那么问题就可以转化为一颗完全二叉树,要使所有长度为(k+1)的链节点之和模(m)为(0)
然后我们把链向上平移一格,发现变的只有一个节点,也就是说每个节点的值都要和它的第(k+1)级祖先模(m)同余。发现不存在(k+1)级祖先的点最多(2^k)个,那么我们只要考虑这$$2^k个点的取值就行。那么树形(dp),设(w_{i,j})表示让所有应该和(i)点取值相同的点都变成模(m)余(j)的最小代价,(f_{i,j})为(i)这棵子树,根节点到所有叶子的值模(m)余(j)的最小代价,那么转移就是(f_{p,(i+j)\%m}=f_{lc,i}+f_{rc,i}+w_{p,j})。不过如果有一些子树里最深的叶子深度小于(k)的话要特判
然后现在的问题就是怎么求出(w)了,暴力的话显然是(O(nm))的。我们设(p)对应的深度小于(k)的节点为(i),用双指针可以(O(n))求出每个节点的(i),然后令(sum[i]+=b[p]),也就是所有和(i)值相等的点的代价和。然后求出(w[i][0]+=(m-a[p]) imes b[p]),之后递推(w[i][j]+=w[i][j-1]+sum[i])就行了。然而这样递推会出一点问题,对于(w[i][j])来说,某些值已经为(j)的点(p)需要多付出(b[p] imes m)的代价,那么只要对于每一个(w[i][a[p]\%m]-=b[i] imes m)就行了
洛谷P5248 [LnOI2019SP]快速多项式变换(FPT)
把(f(m))给(m)进制分解就行了
洛谷P5249 [LnOI2019]加特林轮盘赌
设(q=1-p),易知一只长颈鹿第(i)轮挂掉的概率是(f_i=pq^{i-1}),一只长颈鹿在前(i)轮挂掉的概率是(g_i=1-q^i),那么我们枚举(k)号长颈鹿第几轮挂掉,那么答案就是(sum_{i=1}^{infty}{g_i}^{k-1}g_{i-1}^{n-k}f_i)。继续推倒咱是推不动了,不过考虑到这里没有要我们输出模意义下的值而是保留小数,那么暴力算到(i=200)左右就可以了
loj#2563. 「SDOI2018」反回文串
继续膜拜(shdowice)去