PKUSC2021 简要题解

如果有同学需要我的代码的话可以私我要,题面也可以私

当然由于本人很菜,代码和做法不一定是对的,但是一定是过了自己造的对拍


D1T1 Sum Transformation

假设原矩阵第\(i\)行的和是\(a_i\),第\(j\)列的和是\(b_j\),整个矩阵的和是\(S\)

那么变换一次以后\((i,j)\)的位置就会变成\(a_i+b_j\)

考虑变换的第二次,简单推导一下,\((i,j)\)位置就会变成\(n(a_i+b_j)+2S\)

不难发现,\((i,j)\)位置的值一定可以用\(p(a_i+b_j)+q\)来表示,这个系数对于每一个位置是相同的

这个系数显然可以矩阵乘法递推解决

时间复杂度\(O(logT+n^2)\)



D1T2 逛街

如果没有修改,我们发现把每个\(i\)向最小的\(j>i\)满足\(a_j>a_i\)连边(找不到就往\(n+1\)连),这样会得到一棵树

在树上倍增就可以回答询问

注意到所有的相同的数一定是连成一段的

有修改就意味着一些数可能被覆盖掉,消失了

也就是树上的一些点被删掉了


先考虑sub2,所有修改是对于全局的

不难发现这样我们的删除只会删除叶子

考虑反证法,如果我们修改中删去了一个非叶子节点,那么由于是全局修改,它一定会往它的儿子扩展一步,它就出现在了新的位置,矛盾

于是询问\([l,r]\)我们就只需要在\(l\)处找到树中祖先上第一个还存在的节点,再倍增跳上去,直到跳出当前\(r\)处的范围即可

找叶子可以用st表求区间最大值的位置


考虑sub3,所有修改是任意的

不难发现这样就可能会删除非叶子节点

但是可以看到的是,树的结构并不会改变,因为一个点它的父亲被删除了,它在树上的新父亲一定是它父亲的父亲,姑且称之为爷爷

证明考虑反证,假设它的父亲是\(x\),爷爷是\(y\),能找到的新父亲是\(z\),那么有\(a_y>a_x>a_z\)\(x<z<y\),不难发现此时如果\(x\)\(y\)覆盖掉了,由于\(z\)\(x,y\)中间,所以\(z\)也一定被覆盖了,矛盾

所以这棵树是可以一直使用的

我们删除非叶子节点时并不在树上显式地删除它,而是采取一个懒惰删除的方式,只是把他的权值置为\(0\),查询时查询链和即可

接下来我们还可以证明,尽管可能会删去非叶子节点,但是删去的非叶子节点一定出现在修改区间左端点处

因为只有左端点处的数才不能继续往左扩展,修改区间内部只会删去叶子,这一点的证明跟前面sub2里的证明是类似的


于是一个做法就呼之欲出了

只要我们能够维护每个位置当前的数并支持单点查询,就能够在树上删去非叶子节点的权值,并找到第一个非叶子节点并在树上完成倍增,查询链权值可以用树状数组\(O(logn)\)维护

考虑维护每个位置会对右侧的哪些点取max,不难发现这是一个连续区间,设右端点是\(r_i\),我们只需维护\(r_i\)

于是修改\([L,R)\)其实是让\(\forall i \in [L,R) , r_{i}=r_{i+1}\)

不难发现就是删去\(L\)这个位置的数,并在\(R\)这个位置补充一个原来的\(r_R\)

显然平衡树就是合适的数据结构

总时间复杂度\(O((n+q)logn)\)

代码4.2k,还是挺好写的



D1T3 德州扑克

不会真的有“人”会做吧?



D2T1 一棵树

不删边sb题随便搞

考虑我们删除某条边造成的总贡献

考虑删边后形成的两侧子树A,B中每条边的贡献

对于A中的每条边,他的贡献就是以A中每个点作根,这条边远根处的size之和,再乘上B的size

不难发现我们只需换根dp出以一个点为根,所有点的size和

就可以方便计算出两侧的贡献了

时间复杂度\(O(n)\)

实现细节不少



D2T2 代金券

不难发现一个贪心策略,就是优惠券尽量留在最后来用

发现这样不完全对,优惠券在前面也是可能会使用一部分的,只要不影响获得获得优惠券的数量,也就是\(a_i \ mod\ c\)以内的可以随便用

于是进一步,我们可以归纳出完整的策略

存在且只存在一个\(i\),满足

对于\([1,i-1]\)中的菜品\(j\),我们最多用\(a_j \ mod \ c\)张优惠券,并且尽量多用

对于\([i+1,n]\)中的菜品\(j\),我们能够全部用优惠券支付

对于\(i\)处的菜品,我们用一些优惠券,再用一部分现金来获得优惠券,使得最后恰好优惠券能用完

同时不难发现这个\(i\)满足

\([i,n]\)中的菜品全部使用代金券支付的时候代金券不够用

\([i+1,n]\)中的菜品全部使用代金券支付的时候代金券够用

于是我们只需要找到这个\(i\)即可

因为有修改,暴力维护和查找是\(O(nq)\)

考虑用线段树来维护这个东西

考虑前半部分你对于一个菜品\(j\),假设你当前有\(x\)张优惠券

那么你买它之后的优惠券是 \(x=max(x-a_j\ mod\ c,0)\)\(x+=\lfloor \frac{a_j}{c} \rfloor\) 也就是 \(x=max(x+(\lfloor \frac{a_j}{c} \rfloor - a_j\ mod\ c),\lfloor \frac{a_j}{c} \rfloor)\)

注意\(x=max(x+a,b)\)这样的标记满足结合律,但是没有交换律

\((a,b)\)\((c,d)\)合并以后就是\((a+c,max(b+c,d))\)

于是你可以很方便地维护购买一个前缀以后的优惠券数量

所以我们在线段树上二分就能找到分界点\(i\)

前半部分使用的现金可以用总花费减去用掉的优惠券算出

\(i\)处使用的现金只需二分即可

总时间复杂度\(O((n+q)logn)\)



D2T3 招新

神仙题我写了三个做法来拍

考虑整数部分和小数部分是可以拆开来计算的

我们可以枚举小数部分的大小关系,来计算整数部分的分配方案

最后除以所有满足\(0<x_1<x_2....<x_n<m\)的方案即可,这部分显然是\(m^n\)

具体组合意义的证明可以考虑给小数部分大小排名为\(i\)的确定一个整数部分,这样分配的方案,排序以后,与上面的方案一一对应


做法1:裸暴力

直接\(O(n!)\)枚举小数部分的大小关系,然后接下来的dp是trivial的

\(f[i][j][k]\)表示讨论了前\(i\)个数,第\(i-1\)个数整数部分是\(j\),第\(i\)个数整数部分是\(k\)的方案数

转移前缀和优化下,总复杂度\(O(n!nm^2)\)


做法2:暴力dp

注意到我们的转移只需考虑\(i\)小数部分与\(i-1\)\(i-2\)小数部分的大小关系,并不关心他们在最终的序列中排名究竟是第几

于是我们只需要记在前\(i\)个数小数部分排名中,他们的相对排名即可

\(f[i][a][x][b][y]\)表示讨论了前\(i\)个数,第\(i\)个数小数部分排名是\(a\),整数部分是\(x\),第\(i-1\)个数小数部分排名是\(b\),整数部分是\(y\)的方案

\(b<a\)\(y<x\),从\(f[i-1][b][y][c][z]\)转移过来时需要满足\(c<a \ and \ z \leq x-K\)\(c \geq a \ and \ z \leq x-K-1\),不难发现这是两个矩形,在固定\(b\)\(y\)的时候可以二维前缀和优化

\(b>a\)时同理

总复杂度\(O(n^3m^2)\),极限数据约10s,造数据是够用了


做法3:优化dp

注意到上面的dp转移时当\(x-y \geq K+1\)时,任意\(z \leq y\)均满足条件,而\(z \leq y\)是显然的

于是这启示我们只需记录\(x-y\)的值即可,并且可以把\(x-y \geq K+1\)的合并

修改dp状态

\(f[i][a][x][b][y]\)表示讨论了前\(i\)个数,第\(i\)个数小数部分排名是\(a\),整数部分是\(x\),第\(i-1\)个数小数部分排名是\(b\),整数部分与第\(i\)个数的差是\(y\)的方案,其中\(y \leq K+1\)

\(0 \leq y \leq K\)转移同上略微讨论

\(y=K+1\)时是一个整体和,也可以前缀和处理

总复杂度\(O(n^3km)\),看起来没啥优化

但是请注意当\(\lfloor \frac{n-1}{2} \rfloor k \geq m\)时答案是\(0\),可以直接判掉

所以\(nk\)其实是\(O(m)\)级别的

时间复杂度降为\(O(n^2m^2)\),可以在2s内跑出极限数据

posted @ 2021-05-19 12:16  deaf  阅读(1057)  评论(2编辑  收藏  举报