Loading [MathJax]/jax/output/CommonHTML/autoload/multiline.js

Before NOIP2021

10月末开始会记的少一些。

9.25

P7110 晚秋绝诗

有雾有旗的山可以起到传递作用,把它们删掉之后,如果有两个相邻的无雾的山,那么它们中间的这些都可以确定。对于一个询问,分类讨论,是直接确定,通过左边/右边确定还是两边一起确定。用若干set来维护信息即可。

P4800 [CEOI2015 Day2]核能国度

二维差分,二次差分(在对角线上搞)

P4654 [CEOI2017]Mousetrap

贪心dp一下就行了?写了三种代码,其中一种是线性的。得分72——92。不知道哪里错了,最后只能“特判”。反正思路应该没啥问题

9.26

CF603E Pastoral Oddities

满足条件当且仅当所有连通块大小为偶数。必要性:选出的子图一定是若干偶数连通块,那么原图中的连通块也只能是偶数。充分性:每个偶数连通块选出一个生成树,然后一定可以在树上构造出来(dfs一遍,度数为偶就断开和父节点的边)。
如果暴力算一次答案,只需把所有边排序,依次加入,直到符合要求。因为多加边不会更劣。
对于原问题,根据答案单调性,使用带答案上下界的CDQ分治。给答案一个上下界是为了在递归每一层计算的时候每条边只被修改 O(1)O(1) 次。

P3352 [ZJOI2016]线段树

先考虑容斥转化成01序列处理:枚举 pp,计算最后 axpaxp 的概率,只需要知道 aiaipp 的大小关系,设 bi=[ai>p]bi=[ai>p]
在操作中,11 会向外拓张,00 只能被覆盖。设 fi,l,rfi,l,r 表示 ii 轮后 [l,r][l,r] 全是 00 的概率,分类转移。用前后缀和优化可以做到 O(n3q)O(n3q)
然后发现其实对于不同的 pp 转移的过程相同,而且最终的答案和赋的初值是线性关系。那么直接把每一种答案的贡献弄到 ff 的初值里,递推一遍即可得到所有答案。
因为数列随机,似乎不用优化也是 O(n2q)O(n2q)?
question:"序列随机"意味着对于位置 xxaxax 最后可能得到的值只有 lognlogn 种,能否根据这个条件得到新的做法?

P5466 [PKUSC2018]神仙的游戏

若前缀 ii 为 border,则 nini 为原字符串的一个循环。反过来推也是成立的。
那么只要check nini 是不是循环,也就是看看存不存在一对 si=1,sj=0si=1,sj=0 满足 ij=k(ni),kZij=k(ni),kZ
然后构造多项式,用FFT算出所有可能的 ijij,检查一下 nini 的所有倍数就解决了。

P3565 [POI2014]HOT-Hotels

P5904 [POI2014]HOT-Hotels 加强版

若三个点两两之间的距离相等,则三条路径有且仅有一个公共点,且这个点到三个点的距离相等。枚举这个点,处理出每棵儿子子树内的信息,稍稍优化后计算即可弄到 O(n2)O(n2),通过原始版本。

把上述换根的做法转成定根的dp。转移的时候考虑以 uu 作为三条路径交点,uu 中子树中有 2/32/3 个点讨论。具体的,设 fx,i  gx,ifx,i  gx,i 表示当前遍历完的 subtree(x)subtree(x)dist(x,y)=idist(x,y)=iyy 的数量,gx,igx,i 表示满足 dist(y,lca(y,z))=dist(z,lca(y,z))=dist(x,lca(y,z))+idist(y,lca(y,z))=dist(z,lca(y,z))=dist(x,lca(y,z))+i 的二元组 (y,z)(y,z) 的数量。然后一边累加答案一边转移即可。

写出dp转移后,再用长链剖分优化至 O(n)O(n) 即可通过加强版本。

长链剖分分配空间代码:

void dp (int u, int la, int qwq) {
    int *fx = &f[dfn[u] = ++num], *fy, *gx, *gy;
    if (qwq >= 0) st[u] = qwq;
    else st[u] = id + l[u], id += l[u] + l[u];
    gx = &g[st[u]];
    fx[0] = 1; if (son[u]) dp (son[u], u, st[u] - 1);
    res += gx[0];
    for (int v : G[u]) if ((v ^ la) && (v ^ son[u])) {
        dp (v, u, -1);
        fy = &f[dfn[v]], gy = &g[st[v]];
        for (int i = 0; i < l[v]; ++i) {
            if (i) res += fx[i - 1] * gy[i];
            res += gx[i + 1] * fy[i];
        }
        for (int i = 0; i < l[v]; ++i) {
            gx[i + 1] += fx[i + 1] * fy[i];
            if (i) gx[i - 1] += gy[i];
            fx[i + 1] += fy[i];
        }
    }
}

9.27

P3688 [ZJOI2017] 树状数组

一眼看去,这不就是线段树维护矩阵(或许不用)单 loglog 吗?一阵乱写,竟然 1212 分。啊?这还能错?噢,原来概率不独立啊......

首先询问 l,rl,r 就是问 Al1,ArAl1,Ar 相同的概率是多少, l=1l=1 需要特判。如果分别维护 l1,rl1,r0/10/1 的概率然后再计算,会出问题。因为如果一个区间同时包含 l1,rl1,r,那么他们被修改的概率是相互影响的。

还是得上二维线段树,对于每个 ll 维护所有 [l,r][l,r] 的影响,然后分包含了 l1,rl1,r 中的 0/1/20/1/2 个讨论,复杂度 O(nlog2n)O(nlog2n)

其实还可以用CDQ+扫描线在复杂度不变的情况下将空间优化至线性。

3B1B 有意思的等式证明——看似没有关系答案却和Π相关

3B1B 一个具有启发性的问题

3B1B 物理碰撞模型和Π扯上关系

3B1B 物理碰撞模型和光线反射扯上关系,再到Π

9.28

P5467 [PKUSC2018]PKUSC

不是很难的计算几何问题。画个圆看看多少圆弧在多边形内就好了。

需要的技能:1、判断一个点是否在多边形内;2、求圆与线段的交点。

P6773 [NOI2020] 命运

暴力dp:fx,ifx,i 表示 subtree(x)subtree(x) 中,没满足的条件的最大深度为 ii 时的方案数。转移的时候讨论当前边 (x,y),yson(x)(x,y),yson(x)0/10/1 即可,O(n2)O(n2)。来看看转移方程:

fx,i=(ij=0fx,i×fy,j+i1j=0fx,j×fy,i)+deepxj=0fx,i×fy,jfx,i=(ij=0fx,i×fy,j+i1j=0fx,j×fy,i)+deepxj=0fx,i×fy,j

括号外面的部分是填 11 的情况。

整理一下,设 Sx,i=ij=0fx,jSx,i=ij=0fx,j,有

fx,i=fx,i×(Sy,deepx+Sy,i)+fy,i×Sx,i1fx,i=fx,i×(Sy,deepx+Sy,i)+fy,i×Sx,i1

可以发现,所有 fx,i0fx,i0ii 要么是在 xx 上有限制,要么是从 yy 里弄过来的,这样的 ii 不会凭空增多,符合线段树合并的形式,于是可以用线段树合并来优化转移,复杂度 O(nlogn)O(nlogn)

9.29

Day4 T4

赛时做复杂了。题目要求本质不同,把一般区间dp枚举下标改为枚举下一个值,并利用简单的贪心思想即可做到 O(n2V)O(n2V)。然后发现固定一个端点不动,另一个端点每次移动只会改变一种情况,O(1)O(1) 更新即可。注意统计方案的时候要把旧的区间减去防止重复。

P6776 [NOI2020] 超现实树

分类讨论,递归处理。detail

P6630 [ZJOI2020] 传统艺能

状态设计值得一说。fx,c,0/1/2fx,c,0/1/2 分别表示 cc 次操作后,xxfaxfax 都没标记、xxfaxfax 有、xx 有标记的方案数。然后分类讨论,矩阵快速幂优化。

9.30

P6765 [APIO2020]交换城市

和Kruskal重构树模板不同的是,选出的这些边不仅要让 (x,y)(x,y) 连通,还要让 (x,y)(x,y) 之间的这些东西不是一条链。如果在建立Kruskal重构树的时候对于每棵子树记录“子树内的这些边和点是否构成链”,那么只需要从 LCA(x,y)LCA(x,y) 继续往上倍增跳,跳到第一个标记为"非链"的节点,这个节点的权值就是答案。

如何判断 subtree(x)subtree(x) 在原图中是否构成链呢?这时候得考虑所有边,在不在重构树上的都得考虑。加入一条边 (u,v)(u,v),若 uuvv 未连通,且原来 u,vu,v 所在连通块都是链,且 u,vu,v 都在链的端点时,加入 (u,v)(u,v) 后构成一条链。其它情况都不是链。

P4451 [国家集训队]整数的lqp拆分

非常罕见地看懂了一道数学题,但其实和求斐波那契通项差不多,比较基础。记录一下比较完整的过程。对于斐波那契生成函数,有

F(x)=1x1+1x2+2x3+3x4F(x)=1x1+1x2+2x3+3x4

求封闭形式:xF(x)+x2F(x)+x=F(x)F(x)=x1xx2xF(x)+x2F(x)+x=F(x)F(x)=x1xx2

然后等比数列求和:

G(x)=F(x)i=F(x)1F(x)=x12xx2G(x)=F(x)i=F(x)1F(x)=x12xx2

将分母因式分解,并拆成两个分数之和,得到:

G(x)=x12xx2=x(1Ax)(1Bx)=Ax22(1Ax)+Bx22(1Bx) , A=1+2,B=12G(x)=x12xx2=x(1Ax)(1Bx)=Ax22(1Ax)+Bx22(1Bx) , A=1+2,B=12

发现现在两个分数的分母都是一次了,方向用等比数列求和,可以得到 G(x)=AnBn22xnG(x)=AnBn22xn

这个系数就是要的答案了。

10.01

P4491 [HAOI2018]染色

fxfx 表示答案至少为 xx 的方案数,可得 fx=Cxm×CxSn×(xS)!(S!)x×(mx)nxSfx=Cxm×CxSn×(xS)!(S!)x×(mx)nxS。但其实这里的定义并不准确,它钦定了这 xx 种是哪几种来计算,会产生重复。

然后设 gxgx 为恰好为 xx 的方案数。建立 fxfxgxgx 的关系 fx=my=iCxy×gyfx=my=iCxy×gy,从这里也可以看出 fxfx 相对于定义是有重复的。然后二项式反演,得到 gxgx 的式子,使用 NTT 优化。

10.03

Day5 T4

先写出暴力的dp,若要优化,不可能再记录当前有多少糖果。考虑每次走出一个的时候都把背包塞满,用单调队列记录当前包里糖果分别来自哪里。到了一个点:

1、这段路上产生消耗,把最便宜的糖果拿来消耗

2、一些糖果在之前买的太贵了,不如现在买,把糖“退回去”

3、一些糖果先在中间某点卖掉,再在当前点买回来,可以赚差价。那就进行这次买卖。

因为用单调队列维护,这些操作都是线性的。

本题的优化总结起来就是:把这些操作集中在一点贪心考虑。

10.04

LOJ #6030. 「雅礼集训 2017 Day1」矩阵

基本策略是先把某一行全部染黑,再染所有列。然后枚举一下是哪行就完了。

Day6 T4

想歪了以为是2-SAT+拓扑计数,然后只写了暴力跑路。其实也是一种经典的连边方式,直接连边 (ai,bi)(ai,bi),就能得到美妙的特性了。连完边后,要做的就是给这些边定向,使得每个点入度至多为 11,并且若方向为 (bi,ai)(bi,ai) 会产生 11 的代价。

如果这张图不是树和基环树构成的“混搭森林”,则无解,因为没法让每个点入度 11。然后对于每棵树,如果定了根(无入度的点),所有边方向就定了,可以线性dp一遍求出答案。对于基环树,不在环上的边显然指向外面,环有两种方案,比较一下也就完成了。

10.05

Day7 T3

用奇怪的二分+贪心过了。但我无法证明。第一步肯定让 ci=(aibi+4)%4ci=(aibi+4)%4,我是这样的:

di=cici1di=cici1,然后每次操作 [l,r][l,r] 就是让 dl+1,dr+11dl+1,dr+11。从左往右扫,只有 1,2,31,2,3 三种数,分析一下然后奇怪贪心。

题解的转化稍微特殊一些,即对每个 cici 加上 44 的若干倍(可以是 00),最后答案就是 max(0,cici1)max(0,cici1)。依旧令 di=cici1di=cici1,每次操作就是让 dl+4,dr+14dl+4,dr+14。只有 33dl,dr+1dl,dr+1 的组合能让答案更优,按照一定顺序找出来就好了。

P4457 [BJOI2018]治疗之雨

写出相互之间的关系式后直接高斯消元复杂度为 O(n3)O(n3),但发现这个矩阵非 00 的位置类似一个上三角,所以复杂度可以降为 O(n2)O(n2)

#6033. 「雅礼集训 2017 Day2」棋盘游戏

可以根据棋盘建出二分图,显然一个人是从左部点跳到右部点,另一个人跳回来。如果起点 xx 可以不在最大匹配中,那么先手第一步 通过非匹配边 必然跳到匹配点,后手通过匹配边跳回来,先手又一步跳到匹配点(如果跳到非匹配点,那说明还存在增广路,不是最大匹配),后手又跳回来...最后一定是先手没路走,后手必胜。反之,如果 xx 一定在最大匹配中,那么先手先通过匹配边跳一次,后手必然跳到一个匹配点(否则 xx 可以被替换),然后先手再跳匹配边...最后一定是先手赢。

如何判断某个点是否必须在最大匹配中?不用把每个点去掉求一遍最大匹配,只需要先求出一组最大匹配,然后对于一个点 xx,如果本来就不是匹配点,那么显然不必要;否则从 xx 当前匹配点出发看看能不能找到另外一条增广路,如果可以,说明 xx 可被替换。还有一种方法是使用网络流然后遍历残量网络。本质上应该差不多

10.06

P1971 [NOI2011] 兔兔与蛋蛋游戏

跟上面的棋盘游戏差不多。虽然题目里没说,但其实根据奇偶性,每个点依然只能经过一次,依旧可以用二分图解决。

P6186 [NOI Online #1 提高组] 冒泡排序

ciciii 左边比 aiai 大的数量,逆序对 number=cinumber=ci。每轮冒泡排序就是把每个前缀最大值(即 ci=0ci=0 的位置)移到下一个前缀最大值的左边,除了移动的数 ci=0ci=0 不变,其余所有数的 ci1ci1。那么每次询问就是要求 max(0,cik)max(0,cik),显然只需要分两类计算。每次修改只会改两个点,可以简单维护。

10.07

P6730 [WC2020]猜数游戏

若选了 aiai 后能得到 ajaj,则连边 (i,j)(i,j)。假设已经把这张图建好了,如何计算答案?先求一波强连通分量,强连通分量之间的答案贡献很好计算,现在只考虑一个强连通分量内。因为若存在边 (i,j)(j,k)(i,j)(j,k),则必存在 (i,k)(i,k),所以这个强连通分量其实构成完全图,那么只需要随便给节点定个顺序即可,不妨让编号小的在前面。于是实现的时候不需要去求强连通分量,只要对于每个 xx 枚举 yy ,判断 yy 能否到达 xx。设不能从 yyxxyy 的数量为 cntcntxx 对答案的贡献就是 2cnt2cnt

如何判断是否存在边 (i,j)(i,j)

对于 gcd(ai,p)1gcd(ai,p)1 的,暴力计算能到哪些 ajaj,因为 pp 为质因数的幂次,至多 logplogp 次后就变为 00,所以复杂度为 nlogpnlogp

对于 gcd(ai,p)=1gcd(ai,p)=1 的,显然只能走到 gcd(aj,p)=1gcd(aj,p)=1 的,根据定理 ab(modp)ordpa=ordpbab(modp)ordpa=ordpbordpak=ordpagcd(ordpa,k)ordpak=ordpagcd(ordpa,k),带入关系式 amiaj(modp)amiaj(modp),可得充要条件为 ordpaj|ordpaiordpaj|ordpai

如何计算 ordpaiordpai ?根据 ordpa|φ(p)ordpa|φ(p),可以试除 φ(p)φ(p) 的素因子得到。

对于 gcd(ai,p)1gcd(ai,p)1 的,还有一种方法。设 p=Pmp=Pmai=bi×Pci, aj=bj×Pcjai=bi×Pci, aj=bj×Pcj,当且仅当 acjciiaj(modp)acjciiaj(modp) 时存在边 (i,j)(i,j)

P6478 [NOI Online #2 提高组] 游戏

先树形dp O(n2)O(n2) 算出 gxgx 表示选了 xx 对的方案数(其它的不管)。然后设 fx=gx×(mx)!fx=gx×(mx)! 表示钦定了 xx 对的方案数。有 fx=my=x(yx)×ansyfx=my=x(yx)×ansy,二项式反演得到 ansx=my=x(1)yx×(yx)×fyansx=my=x(1)yx×(yx)×fy,暴力算就好了。

BZOJ3640 JC的小苹果

fi,xfi,x 表示还有 ii 点体力,走到 xx 的概率,不难写出转移 fi,x=fi+ax,y×wx,ydegyfi,x=fi+ax,y×wx,ydegy。由于 axax 可能等于 00,所以不能直接递推,对于每一层(每种体力)需要高斯消元,暴力消元复杂度 (n3hp)(n3hp)

但事实上每一层的矩阵所有系数都是相同的,只有最后的常数不同,所以只需要一遍消元求出常数之间的贡献系数,之后每次 O(n2)O(n2) 计算即可。总复杂度 O(n3+n2hp)O(n3+n2hp)

10.08

P5996 [PA2014]Muzeum

这个问题是最大权闭合子图模型,可以利用网络流暴力求解,答案为物品价值总和减去最大流(最小割)。但数据范围大,考虑优化。(xi,yi)(xi,yi) 能看到 (xj,yj)(xj,yj) 等同于:

xihyiwxjhyjwxih+yiwxjh+yjw

不妨把 (x,y) 变换为 (xh+yw,xhyw),那么条件就变为 xixj,yiyj

按照 x 排序后,用贪心思想模拟网络流:每加入一个警卫节点,找 y 尽量小的手办匹配,因为 y 越大匹配范围越广。数据结构维护一下即可。

P4501 [ZJOI2018]胖

每一条出边能更新一段区间。如果能二分出区间的边界问题就解决了。注意这里不仅要考虑距离还要考虑中间经过的点数。

对于一条边 i,二分边界 mid,此时 mid 的答案只被 pk[mid|imid|,mid+|imid|] 的边更新过,然后要看看通过边 imid 的距离是不是比这些 k 都小。从第 i 条边到 j 的距离:pij: li+dpidj;  pi>j: lidpi+dj。那么只需分别计算 li+dpi, lidpi 的RMQ即可。

这样二分套二分复杂度为 nlog2n 。还可以做到 O(nlogn),比如这个

P3214 [HNOI2011]卡农

如果没有不重复的条件,显然可以对每个二进制位来考虑。但这题直接按照个数来递推。

fi 表示选 i 个元素的可行方案数。所有方案为 (2n1i1),因为选了前 i1 个最后一个就定了;为了不让新选的这个为 0,前 i1 个不能为 0,减去 fi1;为了不出现重复,即前 i2 个为 0,减去 fi2×((2n1)(i2));最后,因为算的是无序的方案数,上述过程会把每种算 i 次,应除掉 i。得到 fi=(2n1i1)fi1fi2×((2n1)(i2))i

预处理一下可以做到 O(m)。如果嫌预处理组合数麻烦,可以先转成计算有序集合的数量,这样只用预处理排列数,最后再除掉 m!

P6830 [IOI2020]连接擎天树

p 很小,直接对 p 分类讨论:

px,y=1,把所有这样的 (x,y) 在并查集中合并,若连通块内存在 p1 则无解。否则随便构造一棵树即可。

px,y=2,把这样的 (x,y) 在另一个并查集中合并,若连通块内存在 p2 则无解。对于大小为 2 的连通块同样无解。否则随便构造一个环即可。

px,y=3,若出现就无解。因为至少存在一对 px,y>3,不符合题目限制。

P6831 [IOI2020]嘉年华奖券

如果每一轮选定了 n 张奖券,那么主办方选中位数,价值就是前 n2 大的减去前 n2 小的。考虑颜色 i 选出的 k 张,其中 smalli 张充当了小的那部分,bigi=ksmalli 次充当了大的部分,显然一定是选了最小的 smalli 张和最大的 bigi 张。初始先让 i,smalli=k,然后进行 nk2 次调整,每次让一个 smalli1,bigi+1,并且每次都选利益最大的那个调整,这个过程可以用堆维护。

假设调整完后得到的答案是 res,原问题的答案是 ans,不难发现 resans,而且一定可以构造出一种方案(根据上述贪心过程),所以 res=ans。构造方案的时候似乎不需要贪心,直接把 big 的从 1k 循环着往里面填就好了 ,code

P4983 忘情

要把长度为 n 的分成 m 段,且明显段数越多越优,考虑WQS二分:二分一个每段的额外代价 C,找到 C 使得最优解 ans 恰好要用 m 段,答案就是 ansmC。对于每次二分,有转移方程 fi=min{fi+(sisj+1)2+C},是一个可以斜率优化的形式:若 j 优于 k,则 si>(fj+s2j2sj)(fk+s2k2sk)2(sjsk),且 si 单增,所以单调队列维护一个凸壳即可。

CF888G Xor-MST

首先,对于权值相同的点,显然可以不花钱就缩成一团。现在没有权值相同的点了。

把这些权值插入trie树,在叶子 (x,y) 间连边,只需考虑 LCA(x,y) 之下的部分。因为权值都不相同,所以恰好有 n1 个可以成为 LCA的点,在这些点贪心地连一条跨越左右儿子子树的边就构成了最小生成树。

具体贪心:从左右儿子出发,每次尽量走同一个儿子,如果两边都有就都走,取 min;如果走不了同一个儿子,就得加上这一层的权值,然后继续向下。注意到在贪心的过程中,有可能两边都要走,复杂度对吗?对每个叶子 x 考虑,走到一次 x 复杂度为 logV,而 x 上方至多 logV 个点需要连边,所以复杂度为 O(nlog2V)

还可以启发式合并trie树来处理,但应该没上面的做法简洁。

10.09

CF1481E Sorting Books

被移动的书顺序随意,但没有动的书顺序固定,且必须同色连成一块,所以对没动过的书进行dp。设 fi 为后缀 [i,n] 中至多保留多少。考虑第 i 本书。

  1. i 是颜色 ai 的左端点,保留所有 ai,则 ficntai+frai+1
  2. i 不是右端点,但仍要保留后缀 [i,n] 中的 ai,那么后缀 [i,n] 中其它的颜色都必须移动,则 ficntai。这里的 cntai 指后缀 [i,n]ai 个数。
  3. 移动 ififi+1

P4425 [HNOI/AHOI2018]转盘

如果从起点开始往后走,中间可能会停下来等待物品出现,不容易想清楚。不妨倒过来,考虑终点在 t,每次往前走一步,物品会在 Ti1 消失,那么马不停蹄一直走最优。(把环拆开复制一遍)不难得到答案为 tmaxi=tn+1(Ti+ti)

写完整并稍微变换可以得到 res=minns=1(s+max2n1i=s(Tii))+n1。这里改成了枚举起点 s,并且 i 的上界改为 2n1,因为后面那些不影响答案。

其中 max2n1i=s(Tii) 表示后缀最大值。可以用单调栈求出对于每一个 jTjj 是后缀 [s,2n1] 最大值的 s 的范围。现在的问题就是动态维护这个单调栈。

用线段树来搞。合并左右子树的时候,右边的单调栈保留;对于左边,在线段树上二分右边最大值在左边“侵占”的位置,更新一下答案。复杂度 O(nlog2n)

P6624 [省选联考 2020 A 卷] 作业题

先对原式进行欧拉反演,得到:val(T)=(wei)×p|we1,p|we2φ(p)

φ(p) 提前,得到:φ(p)×(wei),这里的 wei 只剩下 p 的倍数。

然后枚举 p,后面的部分可以使用矩阵树定理计算。具体的,在矩阵的每个位置记录一个二项式 wix+1,对二项式进行运算求行列式,一次项系数即为答案。

关于行列式、矩阵(线性代数)内容的深入学习还是等NOIP后吧。

P5540 [BalkanOI2011] timeismoney | 最小乘积生成树

这个做法比较奇怪,适用性应该也不广。但还是记录一下吧。

(a,b) 弄到坐标轴上,每个点代表一种生成树方案。找到离 x,y 轴最近的点 A,B(可以直接求最小生成树), CA,B 更优的必要条件是 CAB 下方。找到在 AB 下方的离 AB 最远的点 C(列一下式子,同样可以直接求一遍最小生成树得到),递归处理 CA,CB。一直递归下去直到直线下方空空如也。感性理解复杂度不会太高。

CF1479B2 Painting the Array II

fi,j 表示处理了前 i 个,一个序列的末尾是 i,另一个是 j 时答案的最小值。有转移:

fi,jfi1,j+[aiai1];  fi,ai1fi1,j+[aij]

然后发现,第一个转移就是整体 +1,用一个变量记录即可;第二个转移就是单点修改,同样可以快速完成。复杂度优化至 O(n)

值得一提的是这题还可以贪心。直接维护这两个数列,将 a1,a2,a3an 依次加入,若 ai 和其中一个数列的尾部相同,就加入这一个;否则,设 next 为 和数列尾部相同的 下一个数的位置,将 ai 加入 next 较大的数列。正确性不难理解

P7323 [WC2021] 括号路径

如果 (x,y)(y,z) 合法,则 (x,z) 合法,这样的关系形成团。那么就是要把它们合并在一起。

对于每个点用一个 map 记录每种颜色出边的另一端,若存在多个点可以合并在一起,所以只需要记录一个。

初始的时候,遍历所有边,建出 map,若在过程中需要合并 (x,y),先在并查集里合并,但不合并边的信息,只是把 (x,y) 扔进一个队列。然后,类似于 bfs 拓展的过程,每次取出队首,启发式合并边的信息,然后把新的要合并的若干 (x,y) 加入队尾,直至队列为空。根据并查集里的连通性信息就可以算出答案了。

为什么要先加入一个队列,而不能当场合并呢?其实也可以,这相当于把 bfs 变成了 dfs,再把队列改成栈就可以达到一样的效果。

启发式合并+map 复杂度为 O(nlogklogn),已经可以通过此题。若把 map 改成 hash表或者 unordered\_map,可以降一个 log;当然也可以用线段树合并换掉启发式合并,同样少一个 log

P4640 [BJWC2008]王之财宝

T 小,暴力容斥,枚举不符合限制的物品集合 S,有 ans=(1)|S|f(S)f(S) 直接插板法计算即可,需要用到 Lucas定理:(nm)(m/pn/p)×(m%pn%p)(modp)

P5504 [JSOI2011] 柠檬

不难发现,最优情况下,每段的两端一定相同,而且每段所选的 s0 就是两端贝壳的大小。否则可以缩小当前区间而价值不变,却多出另一段,总和更大。

fi 为前缀 [1,i] 的答案,有 fi=max1ji,si=sj{fj1+si×(ci,sicj1,si+1)2}

按照一般做法,这个式子可以通过斜率优化快速计算。这里记录另一种优化方法。

后面那部分可以看作二次函数,随着 j 减小递增,且斜率越来越大(只考虑 si=sj 的位置)。所以若 j1<j2,且当前 j1 更优,那么之后一直是 j1 优于 j2。而且 j1 首次优于 j2 的时刻可以二分得到。

具体的,对每种贝壳维护一个栈,设栈顶元素为 top,下一个元素为 top1,加入元素 x 时,二分出 top 首次优于 x 的时间 t:若 t 早于当前时刻,不用加入;若 t 迟于 top1 首次超过 top 的时间 t,弹出栈顶,重复此过程,这样栈顶记录的就是最优解了。复杂度比斜率优化多出一个 log

10.10

P3358 最长k可重区间集问题

先把题目转换成:选 k 次,每次选若干不相交的区间,不能重复选,使长度和最大。然后就可以网络流了。

把区间的端点拿出来,排序离散化。连以下几种边:

1、由源点向第一个点连边 (V=k,cost=0),表示可选 k 次。

2、第 i 个点向第 i+1 个点连边 (k,0),表示若不相交可以同时选。最后一个点连向汇点。

3、在每个区间的 li,ri 之间连边 (1,rili),表示只能选一次,价值为 rili

对此图求出最大费用最大流即可。

P1251 餐巾计划问题

把一天形象的拆成白天和黑夜两个节点,连以下边:

1、源点向每个夜晚连边 (V=ai,cost=0),表示一天结束会留下 ai 条脏餐巾

2、白天向汇点连边 (ai,0),因为最终这些边一定满流,相当于限制每天都得有 ai 条干净的。

3、从每个夜晚向下一个夜晚连边,表示脏的留着不洗;第 x 个夜晚向第 x+n/m 个白天连边,表示洗干净;源点向每个白天连边,表示新买餐巾。

对此图求最小费用最大流即可。

本题的关键在于把一天拆成两点,白天流出,夜晚补入,既限制了每天要有 ai 条餐巾,又将脏餐巾保留了下来。

P3355 骑士共存问题

把棋盘黑白染色,会相互攻击的位置颜色不同。那么把相互攻击的关系用边表示,得到的是二分图,要求的就是二分图最大独立集,根据定理有 最大独立集=点数二分图最小点覆盖=点数二分图最大匹配。所以只要求二分图最大匹配。
P2766 最长不下降子序列问题

先用入门dp算出 fi 表示以 ai 结尾的最长序列。在所有长度为 s 的方案中,ai 都只能被放在第 fi 个。所以可以建出分层图,在相邻层之间连边,合理设置边的容量,算最大流即可解决第二、三问。

P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳

先求出凸包,最远点对一定可以被一对平行卡壳卡住(称为对踵点),可以枚举对踵点来计算。

具体实现时,把卡住两点改成卡住一边一点,将点和边的两端分别计算,这样效果不变,运算简单。顺时针枚举边,另一个点显然就是距离这条边最远的点,而且这个点同样顺时针旋转,于是可用双指针可做到 O(n)。但要先求凸包,总复杂度 O(nlogn)

10.11

AT1219 歴史の研究

方案Ⅰ:使用普通莫队,问题变成了 O(nn) 次插入、删除,O(n) 次询问最值。为了不让 nn 再带上 log,通常用值域分块维护答案。

本题答案可能极大,不能直接分块。但不难发现答案其实只有 O(n) 种,离散化后再值域分块即可,复杂度 O(nn)

方案Ⅱ:如果只有插入操作,询问最值,就不需要数据结构维护了。由此想到采用回滚莫队,操作次数仍是 O(nn),每次只要 O(1)max 或者撤销操作即可。

回滚莫队具体实现:先分块,询问的排序方式不变,把 l 在同一块中的一起处理。每次询问先把左指针指在 l 所在块的右边界,然后向左移动到 l,而 r 在同一块中单调,右指针一路向右扫,只加不减。每次先移右指针再移左指针,存储左指针移动带来的变化,询问完后即时撤销。

P6619 [省选联考 2020 A/B 卷] 冰火战士

随着温度升高,一个函数单调递增,一个函数单调递减,两条线取 min,当然在交点处最大。若直接在线段树上二分,复杂度为 O(nlogn)。这些都是很容易想到的,但是被卡常了,本题需要在树状数组上二分。

具体的,初始二分边界 l=1,r=2k,右边界设为 2k 是为了让 treemid 存储的刚好是 [l,mid] 的和。然后就可以快速二分了。

P2447 [SDOI2010]外星千足虫

若能解出所有未知数,需要至少 n 个相互独立(不能相互推得)的方程。把每个方程看成一个二进制数,就等价于 不能通过其他数异或得到。这个问题当然用线性基解决,使用 bitset 优化后复杂度为 O(n3w)

P6628 [省选联考 2020 B 卷] 丁香之路

将原题转化为:图中初始有 m 条边,需要添加若干条边,使得所有度数不为 0 的点、 st 连通,且存在从 st 的欧拉路,求添加边的最小长度和。

欧拉路的条件是 s,t 的度数为奇,其余为偶。从左到右遍历 x,若 x 度数不满足条件,则连边 (x,x+1)。这些边代价都为 1 且不相交,所以花费最小,同时尽量减少了连通块个数。

然后用最小生成树来保证连通性。因为本题边权特殊,考虑相邻两点之间的边即可。为了维持度数奇偶性,新加的树边都要两条。

两步处理完得到的就是最优解了。上述过程保证了添加的非必经边不相交,感性理解正确性可以保证。复杂度为 O((m+n2)logn)

P6622 [省选联考 2020 A/B 卷] 信号传递

拆拆拆!把路径的代价拆出来分别计算,就可以暴力状压dp了。然后递推预处理优化到 O(m2m)。然而这题的重点在于卡空间

P2597 [ZJOI2012]灾难

如果能根据支配关系建出一棵树,问题就解决了。x 的支配点是所有 x 前驱节点在支配树上的 LCA。只要在拓扑排序时顺带着计算即可。

P1912 [NOI2009] 诗人小G

和 10.09-P5504 [JSOI2011] 柠檬 如出一辙的决策单调性优化,这类题目的dp转移式中都有一个斜率单调的函数,比如常见的幂函数。

P4965 薇尔莉特的打字机

一眼看去以为是要在 trie 上搞了,但其实只要“假装有一棵trie树”,然后计数就行。fi 的定义不是很好想。

具体的,设 fi 表示没有儿子 i 的 可拓展的 节点数。原字符串在树上构成链,一开始只有最后一个点可拓展。

加入字符 x,新增 fx 个节点,把除了 fx 之外的 fi 都加上 fx

删除 x,初始链上多出一个可拓展的点,给除了原有的一个儿子外 fi+1

复杂度 O(26n)

10.12

BZOJ4544 椭圆上的整点

移项得到 3y2=r2x2=(r+x)(rx),令 d=gcd(r+x,rx),A=r+xd,B=rxd,原式变为 3y2=A×B×d2

3y2 为完全平方的 3 倍,d2 为完全平方,那么 A,B 其中一个为完全平方,另一个为完全平方的 3 倍,且 gcd(A,B)=1。设 A=3a2,B=b2,有 A+B=3a2+b2=2rd

先枚举 d,然后枚举 a,判断是否存在 bgcd(A,B)=1,统计答案即可。复杂度和 2r 的约数个数有关,假设约数个数为 2r,复杂度上界为 O(2ri=1(i+2ri)=2ri=1i+2r2ri=11i)=O((2r)1.5)=O(r0.75)。当然这是远远不满的。

P2508 [HAOI2008]圆上的整点

显然可以用和上一题一样的方法解决。但本题有更奇妙更优秀的做法。

把问题搬到复数域里,a2+b2=r2(a+bi)(abi)=r2,问题变成了求 有多少个高斯整数(a,b 为整数的复数) Z 满足 ZׯZ=r2

类比于整数域的质因数分解,复数域同样可以“素数分解”。若高斯整数 p 不能被表示为若干高斯素数的乘积,则称 p 为高斯素数。

如何判断一个数是否为高斯素数?使用费马平方和定理:奇素数可以表示为两个正整数的平方和,当且仅当 p1(mod4),且方案唯一。(可表示为两个正整数平方和 与 p+0i 不是高斯素数等价)

铺垫结束。把 r2 在整数域内质因数分解:r2=2nAj=4k+1ApjjBj=4k+3Bqjj,分类讨论:

对于非高斯素数 Aj+0i,可以拆成 zj,¯zj,必须一个分给 Z,一个分给 ¯Z。和计算约数个数时一样,Z 可以得到 0,1,2pizj,所以对答案的贡献为 pj+1

对于无法分解的高斯素数 Bj+0i,必须给 Z,¯Z 分配相同个数的 Bj。所以若 2|qj,仅存在一种方案;否则答案为零。

对于 2n2+0i=(1+i)(1i),看似和 Aj 是同类的,但 1+i,1i 的夹角是 90,旋转后并不能产生更多的答案,不用去管。(答案 a+biabi,b+ai,bai 成对出现,已经 ×4 了,别重复计算)

分解 r2 只需分解 r,复杂度为 O(r)

CF613D Kingdom and its Cities

每次询问选 k 个点进行,明摆着要建虚树。

虚树的建立:用栈维护最新的一条树链,把 k 个点按 dfs 序排序后依次加入:若栈为空,直接加入 x;否则,取 lca=LCA(u,stk[top]),若 lca=stk[top],树链继续延长,直接加入 x;否则,出现分叉,把 lca 之下的这段树链连边并弹出,然后加入 lca,x

接下来简单地dp一下即可。

P1654 OSU!

三次的期望和不等于期望和的三次。要从一次推到二次,二次推到三次。

P2260 [清华集训2012]模积和

复习一下整除分块:对于 in,最大的 使得 ni=nj 成立的 j=nni。每次把 [i,j] 一起计算,然后让 i=j+1。因为 ni 最多有 2n 种取值,复杂度为 O(n)

之后就简单了,先把 ij 的限制扔到后面,得到 ni=1(n%i)×mi=1(m%i)min(n,m)i=1(n%i)×(m%i)

然后把 (n%i) 都写成 ni×ni,前面乘号两边的式子直接整除分块计算,后面的先把括号拆开再计算。

CF452F Permutation

把问题转移到 a 的逆序列 bbai=i)上,问题变成是否存在 bxt<bx<bx+t。枚举 x,定义 cp=[bp<bx],那么只要看看从 x 开始向两边延伸的0/1串是否相等。

这提示我们利用哈希:如果按照 bx 大小顺序来枚举 x,每次只会改变一个 cp,用线段树维护0/1串的哈希值比较一下即可。

10.13

CF1406E Deleting Numbers

暴力做法:枚举每个质数 p,执行一次删除 p,然后询问 p,p1,p2,看看 x 含有 p 的几次。

基于 x 至多含有一个 >n 的素因子,可以进行根号分治。定义 n 的质数为小素数,其余为大素数。

对于所有小素数执行暴力做法,此时集合中只剩下 1,x 和所有大素数。

x 为合数,并且含有 n 的因子 P,那么当且仅当询问 P 时答案为 2,对于所有大素数询问一次即可。

x 为大素数,似乎又要执行暴力做法了。但这时可采用分块优化,删除 B 个后再询问一次 1,看看 x 在不在其中,如果在这 B 个里,暴力这 B 个,否则继续检查后面的 B 个。询问次数成功开平方。

P5610 [Ynoi2013] 大学

一个朴素的想法:用 5×105set 维护每个数倍数的所有下标,修改的时候在对应 set 中遍历区间内的元素。一个元素被修改的时候不需要马上修改与之相关的 set,下次用到的时候再判断即可。

这样做显然过不了 Ynoi。上述的 set 只删不加,杀鸡焉用牛刀,可以换成 vector + 并查集:vector 替换 set,并对每个容器维护一个并查集,删除 x 的时候,在并查集上将 x 并入后一个元素。其实并查集中 fax 记录的就是 x 之后第一个未被删除的元素。

像这样仅在一个序列上合并的并查集复杂度为 O(α(n)),而一个数最多被删除 logV 次,这部分是 O(nlogVα(n))。还要用树状数组维护区间和,O(nlogVlogn)。应该跑不满,卡卡常可过。

CF611H New Year and Forgotten Tree

对于每种位数钦定一个“核心点”。任何一种方案都可以转化为 没有两个非核心点相连 的情况。

核心点数量只有 6,那么核心点之间的连边可以爆搜出来。对每一种寻找方案。

根据定义,任意一个非核心点 x 的度数为 1(若 >1 必成环),只能匹配一条边。

1、对于同种位数的连边,只能匹配一种点。这部分先处理掉。

2、对于不同位数间的连边,需从两种点中选一种匹配。这显然是一个网络流模型,建出图跑一遍最大流看看流量是否正确。如果可行遍历残量网络找出方案。

CF627E Orchestra

枚举左上角然后使用尺取法复杂度为 O(r2c)。注意到 k 很小,把重心放到有点的这些位置上。

按照以 列、行 分别为第一、二关键字的顺序,用链表维护所有点,并对每个点记录之后第 k1 个点所在的列。然后枚举上边界 U,下边界 DD1 时,需要从链表中删除这一行的点,每次删除只会影响前 k 个位置,暴力修改即可。在修改的时候可以顺便维护左右边界方案数的变化。复杂度为 O(rnk)

P3287 [SCOI2014]方伯伯的玉米田

“修改一段区间”可以改成“修改一段后缀”,那么就可以 dp 了:设 fi,j 表示第 i 个数加了 j,以 ai 结尾的最长序列。如果把 (j,ai+j) 扔到二维平面上,转移的时候就是要求左下方元素的最大值,使用二维树状数组维护。

51nod 1317 相似字符串对

要满足 A+C=C+B=S,若存在 C,必定能够让 |C|<n,否则 S 的前面一段是若干个 A,可以删掉只留一个。

D=S[|C|+1,n],原条件可以转化为存在 C,D,使得 A=C+D,B=D+C。对于每个 A,设其最小循环节长度为 m,那么只能得到 mB

于是设 fi 表示最小循环节长度为 i 的字符串数量,容斥可以得到 fi=kij|ifjanswer=fi×in 的因数很少,暴力算就好了。

10.14

P3179 [HAOI2015]数组游戏

SG函数基本内容:把博弈游戏转化到有向图上,每个节点代表一个状态。SG(x)=mex{S},其中 Sx 的后继节点SG值集合。假设游戏起点集合为 PV=SG(x1)SG(x2)SG(xk),xiP,当且仅当 V0 时先手必胜。

举个例子,对于 Nim 石子游戏,可以把每堆石子上进行的过程看成一张有向图。设节点 x 代表剩了 x 个式子的状态,这张图形态特殊,x 向所有 y<x 连边,所以 SG(x)=x。一共有 n 堆式子,每堆石子的起点为 ai,令 V=SG(a1)SG(a2)SG(an)=a1a2an,当且仅当 V0 时先手必胜,这就得到了广为人知的经典结论。这是最简单的应用,使用SG函数还可以对各种复杂变式轻松处理。

对于本题中的翻棋子游戏,同样可以转化到有向图上使用SG函数。如果把 n 个棋子一起考虑,状态显然过于复杂。尝试通过一定的转化把每个棋子独立出来。

类比于上面的 Nim 石子游戏,把第 x 个棋子(只考虑白的)看成大小为 x 的石堆,令 V 为所有石堆大小的异或值。若翻转了 x,2x,3xkxVVx2xkx,相当于删除了大小为 x 的石堆,加入大小为 2x,3xkx 的石堆。

这样一来每个棋子都成了一个独立的游戏,根据SG定理,有 SG(x)=mex{0,SG(2x),SG(2x)SG(3x),SG(2x)SG(3x)SG(4x),...},最终答案为白棋子位置 SG 值的异或和。

不难发现,nx=nySG(x)=SG(y),于是可以进行整除分块只计算 n 个位置,计算每个位置时再次分块,利用异或前缀和计算答案。

复杂度为 O(ni=1(i+ni)=ni=1i+nni=11i)=O((n)1.5)=O(n0.75)

P4318 完全平方数

转化为二分+判定。判定就是要求出 [1,n] 内有多少数符合要求。直接容斥,用总数量含至少奇数个质数的平方因子的数量+含至少偶数个质数的平方因子的数量。根据 μ(x) 的性质,正好可以把它作为系数,得到答案为 ni=1μ(i)×ni2

CF1139D Steps to One

使用公式 E(X)=P(Xi),接下来要求出 P(Xi),等价于求 P(X<i),也就是要求长度为 i1gcd=1 的序列数。这个问题和上面的P4318十分类似,同样使用 μ(x) 作为系数进行容斥:μ(j)mji1

于是有 E(X)=1+i2mi1mj=1μ(j)mji1mi1=1i2mj=2μ(j)mji1mi1

调整枚举顺序:1mj=2μ(j)i1(mjm)i

套用公式 i1xi=x1x (x<1) 得到 1mj=2μ(j)mjmmj。干就完了。

BZOJ4977 跳伞求生

根据网络流图的特殊性质优化暴力费用流(模拟费用流)。

先将队友和敌人放在一起按弹药数排序,若相同让队友在前面。然后依次处理队友 i,其贡献为 aibj+vj。根据最简单的贪心思想,用堆维护 bj+vj 的最大值,把它匹配给 i

但在网络流模型中,局部最优显然无法推出全局最优,所以还要模拟费用流的“反悔”操作。具体的,匹配了 (i,j) 后,将 bj+vj 弹出,加入 ai。如果 i 选了 ai,相当于用 i 换掉 i,反悔了 (i,j) 的匹配。

执行以上“可反悔(替换)贪心”的效果等同于费用流。

一顿操作有些迷。不禁想问:怎样的模型可用模拟费用流优化呢?观察上面的表达式,i,j 对于匹配的价值的贡献相互独立,所以可用堆来维护部分价值的最优解。

LOJ6089. 小 Y 的背包计数问题

对于体积 >n 的物品,肯定用不完,可以看成完全背包。如果暴力计算复杂度为 O(n2)。换一种方式填充:每次往背包里加入一个大小为 n 的物品,或让背包里物品体积都 +1。设 gi,j 表示有 i 个物品,总体积为 j 的方案数,然后递推。因为至多用 n 个物品,复杂度为 O(nn)

对于前 n 种物品,将多重背包计数转化成完全背包:先按照完全背包递推一遍,然后减去不符合限制的方案数。只需倒序枚举 j,令 fi,jfi,j(i+1)×i

两种都算完后 O(n) 合并起来就是最终答案。

10.15

BZOJ5003 与链

拆开考虑二进制下每一位的权值 2p,根据图的性质,如果 2p 的数量定了,那么方案唯一。

现在问题变成了:有 p 种物品,第 p 种价值为 2p,有 k 个,求选取若干物品使得总价值为 n 的方案数。

和上一题LOJ6089中 n 的物品的处理一样,先求完全背包的方案数,然后减去超过限制的部分,复杂度为 O(nlogn)

P6623 [省选联考 2020 A 卷] 树

x 处合并 yson(x) 的答案时,需要:加入 vx;合并 son(y) 内的数;给所有数+1;查询异或和。

使用trie树维护答案,除了全局 +1 之外都是常规操作。+1 会导致从低位到高位的进位,那么把trie从低位到高位倒着建(反正不求最值)。+1 在这一位的影响等同于交换 0/1 儿子,还要考虑进位:在交换前权值为 1 的子树里继续向下递归修改。

单次+1修改修改复杂度为 logVtrie 合并复杂度为 nlogV,总复杂度 O(nlogV)

其实还可以找规律+差分

P6097 【模板】子集卷积

FWT 可以解决 i|j=k 的限制。对于 i&j=0,转化为 pop_count(i)+pop_count(j)=pop_count(k)。那么把下标 i 分到第 pop_count(i) 组,在符合要求的两组间进行 FWT,就同时满足了两个条件。

P3822 [NOI2017] 整数

结论:如果对一个二进制数多次执行高精度+1,暴力进位,每次均摊复杂度为 O(1)。回到本题,每次加一个有 log|a|1 的二进制数,如果暴力进位计算,复杂度为 O(nlog|a|)

但如果有加有减,复杂度没有保证,所以只能分别维护加、减的总和 A,B。询问 k 的时候要考虑退位,只需要知道 k 之后 A,B 第一个不同的位置谁大。用 set 维护所有不同的位置,上述过程可用 lower_bound 查找。每次最多修改 log|a| 个位置,还得在 set 中操作,复杂度为 O(nlognlog|a|)。使用二进制压位优化,可去掉一个 log

10.18

P3290 [SCOI2016]围棋

设当前处理的模板为 T。每一行有 3m 种填法,对每种填法用 kmp 处理其与 T 的第一/二行的匹配关系,复杂度 q3mm

然后设 fi,j 表示处理了前 i 行,第 i 行与 T 第一行匹配的位置集合为 j 时的合法方案数。考虑转移:3m 次枚举当前行的填法 T,设 TT 第一/二行的匹配关系为 A,B,有 fi,A+=jB=fi1,j。只要用 fwtfi1, 进行预处理就可以 O(1) 转移了,复杂度 n3mq+n2mq

总复杂度为 O(q3m(n+m))

P3336 [ZJOI2013]话旧

如果题目条件为“最小值是0”,那么可以转换成从 (0,0) 走到 (n,m) 且不穿过 y=xb 的方案数。这是 catlan 数的经典模型之一。推导过程:总方案数为 (n+mn),不符合条件的路径和从 (0,0)(m+b,nb) 的路径一一对应,方案数为 (n+mnb),所以答案是 (n+mn)(n+mnb)

本题的条件是"极小值为0",意思就是所有 f(x1)>f(x)<f(x+1)f(x)=0,那么如果向下走就必须走到底了。设 fi,0/1 表示走到 ai,从 ai1ai 的直线向上/下的方案数。

如图,A,B 代表相邻的定点。先把 A,B 向右下、左下拉到 x轴,设这两点为 (xi1,0)(xi,0),这两点间的路径方案数相当于把 k=xixi12 个物品分成任意段,容易得到答案 2k1。这个就是 fi1,1fi,0 的贡献系数。对于 fi1,0,先沿黄虚线向上一段(可为 0),然后一样,方案数为 20+21+22+2k1=2k1,但它还可以只有一上一下,总共是 2k。综上,fi,0=2k1fi1,1+2kfi1,0

事实上,fi,1fi,0 的转移是一样的,因为把最后一段折线向上翻(绿虚线),两者一一对应。

P1973 [NOI2011] NOI 嘉年华

先解决第一问:设 fi,j 为在时间 [1,i] 内,A 选了 j 个,B 最多的数量。枚举一个 k,分类讨论 [k,i] 之间的区间给 A 还是给 B,从 fk1, 转移,复杂度 O(n3)

对于第二问,先按上述方法预处理前缀后缀的答案,然后枚举一个包含线段 i 的区间,再将前后缀的答案合并。看样子是 n×n2×n2 的,但事实上,区间总共只有 n2 个,而合并的时候也可以利用单调性去掉一个 n,复杂度变为 O(n3)

P5527 [Ynoi2012] NOIP2016 人生巅峰

若区间长度为 l,那么选出一个非空集合有 cnt=2l1 种选法。若 cnt>1000l,即 l>13,则至少存在 2 种权值一样的选法 A,B,设 C=AB,那么 AC,BC 就是一组可行的方案,所以答案定为 YES

现在只剩下长度 13 的区间。先预处理在 %v 下三次幂运算的循环节,然后记录每个数被修改的次数,就可以算出这 10 个数当前的值了。然后直接暴力或者折半处理即可。

如果不处理循环节(烦),也可以用拓展欧拉定理:

ab{ab%ϕ(p)           gcd(a,p)=1ab                  gcd(a,p)1,b<ϕ(p)ab%ϕ(p)+ϕ(p)    gcd(a,p)1,bϕ(p)       (mod p)

P4463 [集训队互测 2012] calc

为了方便 dp,先指定序列递增,最后再乘上 n!。设 fi,j 表示前 i 个数,最大数 j 的方案数,显然有转移 fi,j=fi,j1+fi1,j1×j。接下来就非常不错了。

结论:对于 k 次函数 f(x)f(x)f(x1)k1 次函数。

fi,jjg(i) 次函数。移项得到 fi,jfi,j1=fi1,j1×j。那么 fi1,j1×jjg(i)1 次函数,得到 g(i)1=g(i1)+1,所以 g(n)=2n。于是先算出前 2n 个值,然后就可以用拉格朗日插值得出多项式,快速计算答案了。

拉格朗日插值公式:F(x)=ni=1ji(xxj)ji(xixj)yi。注意只能选定义域内的点。

BZOJ4589 Hard Nim

pi 表示 i 是否为素数。fi=jk=ipj×pk,表示只有两堆石子时异或值为 i 的方案数,那么 n 堆石子只要卷上 n 次(用快速幂、异或 fwt 优化),然后 f0 就是答案。

异或 fwtFWT(A)=merge(FWT(A0)+FWT(A1),FWT(A0)FWT(A1))

P6815 [PA2009]Cakes

先给每条边定向,由度数较小点指向度数大的点,于是此图成了 DAG。然后在图上枚举三元环:枚举 i,枚举 ij 打上标记,再枚举 jk,若 k 被打上标记则构成了三元环。

复杂度多少呢?记 dii 的度数。若 dimi 的出边数显然 m;若 di>m,根据连边的方式,i 出边依旧 <m。而枚举出边的总次数为 m,所以总复杂度为 mm

10.19

BAOJ3569 DZY Loves Chinese II

断开一些边后,若图不连通,则必定可以找到一个断边子集 SS 中有一条树边,和所有覆盖这条这条边的非树边。现在问题就是如何判断是否存在这样的子集。

随便搞一棵生成树,给每条非树边随机一个权值,树边的权值为覆盖它的非树边的权值异或和。若存在上述 S,只需找出一些异或和为 0 的边,可用线性基判断。

P5327 [ZJOI2019]语言

暴力做法:对每个点 x,求包含 x 的链的并集大小。求并集可使用线段树区间覆盖完成。

转化一下,把链 (x,y) 拆成 (1,x),(1,y),并减去多出来的 (1,fa[lca(x,y)])。前面的部分就是求若干 (1,xi) 的并:把所有点按 dfs 序排序,答案是所有点的深度和减去相邻两点 LCA 的深度和,在线段树上对应单点修改。对于后面要减去的部分,因为这些链相交,所以只要减去所有点 LCA(即 dfs 序最小和最大的点的 LCA)的深度。

在处理 x 的时候,直接继承 yson(x) 的信息(线段树合并),并加入在 x 点的变化。复杂度 O(nlogn)O(nlog2n)

BZOJ2741【FOTILE模拟赛】L

首先定义 bia 的异或前缀和,询问就被转化成求 bxby  x,y[l1,r] 的最大值。

n 个元素分为一块。使用可持久化 trie 树和暴力可在 nnlogn 时间内算出所有 si,j 表示块 [i,j] 内的答案。

对于每次询问,中间整段块的答案已经有了,只剩下两边 n 个数和其他数异或的答案没算,还是 nnlogn 暴力即可。

BZOJ4184 shallot

只有加入、区间查询,强制在线:对每一个前缀维护线性基,原本线性基的每一位取的是最靠左的数,现在改成最靠右的数,就可以处理询问了。

然而本题又要加,又要删。把所有操作离线,弄到时间轴上,相当于在时间 [l,r] 加入 x,并询问某个时间的答案。正符合线段树分治的形式,复杂度 O(nlognlogV)

P3350 [ZJOI2016]旅行者

网格图分治。每次取长边两中点连线 L 切开,计算 L 上点到其他点的最短路,用经过 L 的路径更新询问答案(只更新两点都在当前矩形内的),并递归下去。每次选的短边长度 Lnm,所以复杂度有保证。

10.20

P3247 [HNOI2016]最小公倍数

每次询问只能加入 aiA,biB 的边。把边和询问按 a 排序,双指针加入 aiA 的边,第一个条件就解决了。

然后对第二个条件分块处理:维护 cnt 个并查集,第 i 个记录加入 bi 最小的 mcnt×i 条边后的连通性。每次询问的时候先找到 B 所在块的前一个并查集,那么至多只有 mcnt 条边没被加入,暴力加入并撤销。复杂度 O(cnt×mlogn+qmcntlognmqlogn)

虽然本题的并查集需要撤销,但只有加入零散的 mcnt 条需要撤销,其它修改还是可以路径压缩的,所以 logn 好像可以变成 α(n)

P3250 [HNOI2016]网络

整体二分:对所有询问一起二分、判定。

二分答案为 mid,修改 mid 的边并对每个询问判定。撤回修改。然后把答案 mid 的询问扔到右边,<mid 的扔到左边,边也一样,再递归下去。

对询问一起判定的过程:加入链,清除链,看看当前有无不经过 x 的链。实际上只要知道 x 被多少条链覆盖了,树上差分转化成单点修改和区间查询,用树状数组维护。

DAG 计数

对一张 DAG 枚举零度点集合 S,设剩下点的集合为 T,它们之间的连边方向只能 ST。但 T 中可能存在其它零度点,所以要乘上容斥系数 (1)|S|+1。 递推的时候枚举 |S|,得到 f(n)=ni=1(1)i+1(ni)f(ni)2i(ni)

P3175 [HAOI2015]按位或

min-max 容斥:max(S)=TS(1)|T|1min(T)。推导过程:给 S 排序,设容斥系数为 f(i),写出 S 中每个数的贡献,转换到函数 g(n)=[n==0],然后二项式反演算出 f(i)。可以拓展到第 k 大: kthmax(S)=TS(1)|T|k(|T|1k1)min(T)

回到本题,套用 max(S)=TS(1)|T|+1min(T)。其中,S 里包含每个 1 出现的期望时间。问题就变成了求 min(T)。有 min(T)=1iTpi=11iT=pifwt 处理分母就好了。

P3331 [ZJOI2011]礼物

先把三维转二维,剖出第 k 层,计算以 (i,j) 为右下角的最大正方形边长 fi,j,kfi,j,kmin(fi1,j,k,fi,j1,k)+1,从上界开始向下枚举,直到可行。这样暴力每个点均摊 O(1),总复杂度 O(n3)

然后再 dp 拓展回三维:对每个 (i,j) 若选了 [l,r] 层,答案为 (rl+1)×minrk=lfi,j,k,于是可以枚举每个 p 作为最小值,用单调栈求出 fi,j,p 为最小值的 l,r 的边界,更新答案,这部分也是 O(n3)

P6665 [清华集训2016] Alice 和 Bob 又在玩游戏

定义 SG(x)subtree(x) 内游戏的 SG 值。最后答案为每棵有根树 SG(root) 的异或和。问题变成对每棵树求解 对于 x,得到了所有 SG(y)  yx,ysubtree(x),如何求 SG(x)

按照定义,需要计算每个后继状态的值,也就是枚举删除链 (x,y),对删完后分成的若干棵树的 SG(root) 求异或和,再对这些值求 mex

考虑优化这个过程。y=x 容易计算。假设 ysubtree(z),zson(x),删除之后 subtree(z) 内的值为 ZV=xorpson(x)SG(p),最终答案就是 ZVSG(z)。当 zx 后 ,ZVSG(z) 取值集合中的所有数异或了 VSG(y),并且要合并所有 zson(x) 的信息,可用 trie 合并、全局异或解决;至于询问 mex,直接在 trie 树上二分。

10.21

P4224 [清华集训2017]简单数据结构

注意到本题的特殊限制有“元素两两不同“”每个数最多插入 10 次“,它们为暴力做法提供了复杂度保障。

”元素两两不同“暗示答案长度至多为 logV,对每个位置维护 fi 表示以 i 为开头的最长序列,gi,j 表示以 i 为开头的长度为 j 的序列可以从多少个地方转移。同时记录 ansi 表示长度为 i 的序列的不同开头数。

在开头加入 x,只需枚举 x 的倍数向 x 转移,每个数最多插入 10 次,上界是 10qlogV。在开头删除 x,直接在 ans 里修改然后删除。

在末尾加入/删除 x,先枚举 x 的因子进行修改(称这个过程为 upd),然后从大到小枚举 x 的因子 y,如果 fy 发生变化,执行 upd(y)。看着挺暴力,但由于条件限制,复杂度还是对的。

P4247 [清华集训2012]序列操作

k 很小,在线段树的每个节点上都记录 k 个值,分别表示在区间内选 1,2,k 个数的答案。合并两个节点的时候 k2 暴力卷积即可。

对于取反操作,相当于让选奇数个数的答案取反,选偶数个的不变。

对于区间加 vx1x2xn(x1+v)(x2+v)(xn+v),展开可得 vjfi 的贡献系数为 fij×(L(ij)j)

于是所有操作都可以在线段树上处理了,复杂度 O(k2nlogn)

P3706 [SDOI2017]硬币游戏

S 为还没结束的状态(概率),Ti 为第 i 个人获胜的状态。

要在 S,T 之间建立关系。能不能直接在 S 后面加上 si 然后就和 Ti 扯上呢?显然不行,因为可能还没得到 si 先得到了 sj。此时有 si[1,k]=sj[mk+1,m],即 S+si[1,m]=Tj+si[k+1,m]

于是可对每个 si 列出关系式 12mS=nj=1mk=1[si[1,k]=sj[mk+1,m]]12mkTj,还有 Ti=1n+1 个式子 n+1 个未知数,高斯消元 n3 求解。

P2371 [国家集训队]墨墨的等式

V=minai,若能表示出 kV+r,必能弄出 (k+1)V+r,所以只要知道对于每种 r,最小的 k 是多少。

%V 的余数间连边:对每个 ai 枚举 rr(r+ai)%V,权值为 r+aiV。然后从 0 开始求单源最短路即可。

这里选最小的 ai 与正确性无关,只是为了快一点,省一点。

P4466 [国家集训队]和与积

d=gcd(a,b),a0=ad,b0=bd,原条件变为 (a0+b0)d|a0b0d2(a0+b0)|d

不难发现,a0+b0dnb0,所以 a0,b0n,可以快乐地枚举 a0,b0

na0=1nb0=a0+1nb0a0+b0[gcd(a0,b0)=1]

带入莫比乌斯反演,并更改枚举项、变换枚举顺序,得到:

nd=1μ(d)ndb0=22b01t=b0+1nb0d2t

枚举 d,b0t 可以数论分块,复杂度大概是 O(n0.75logn)

P4586 [FJOI2015]最小覆盖双圆问题

先看看单圆覆盖。设当前点集的最小圆覆盖为 C,若新加入一个点 Pi 不在 C 中,则 Pi 一定在新的最小覆盖圆上,固定 Pi 并暴力重构:初始化圆心为 Pi,半径为 0;然后枚举第二个点 Pj(不在当前圆内),此时有两个点,令圆心为 PiPj 中点,r=dist(Pi,Pj)2; 最后枚举第三个点 Pk(不在当前圆内),此时三点定圆。

说的不是很清楚,放一个伪代码:

for (i = 1 to n) if (P[i] 不在 C 内) {
	C = {P[i], 0};
	for ( j = 1 to i - 1) if (P[j] 不在 C 内) {
		C = {0.5 * (P[i] + P[j]), 0.5 * dist (P[i], P[j])};
		for (k = 1 to j - 1) 
			if(P[k] 不在 C 内) C = 外接圆 (P[i], P[j], P[k]);
	}
}

复杂度多少?把点随机打乱后,Pi,Pj 不在 C 内概率为 3i,3j,期望复杂度 O(ni=1(3i×(ij=13j×j))=9n)

本题要求双圆覆盖,显然能够找到一条线 LL 的左侧用第一个圆,L 的右侧用第二个圆覆盖最优。先枚举 L 的倾斜角,每次转过 π100,然后还要确定截距。暴力显然是不行的。发现随着截距改变,左侧最小覆盖圆半径 R1 递增,右侧 R2 递减,而要求的是 min{max(R1,R2)},如果画成函数图像,一定在交点处最优,所以二分交点求解。复杂度 O(200nlogn)

P2172 [国家集训队]部落战争

最小路径覆盖:把每个点拆成入点和出点,按照题意连边。每选一条边,相当于合并两条路径,数量 1,所以答案是总点数 二分图最大匹配。

P3653 小清新数学题

筛出 [1,106] 内的素数,统计这部分素数的贡献。对于剩下的数 x,最多由两个 (106,1018] 的素因子相乘,分类:1、用 MillerRabin 检测后是素数;2、是平方数;3、剩下的都是两个素因子相乘。统计一下就好了。

MillerRabin 素数检测:针对较大值域的单个数进行素数判定。费马小定理 ap11(modp),反过来不一定成立,称 ap11(modp) 但不是素数的 p 为伪素数。发现对于每个 a>1,伪素数个数小于素数的 14,可以多测几个 a 来判断 x 是否为素数,正确概率极大。这种做法比较简单,要注意对 a=x 特判。

可以使用二次探测定理提高测试效率。二次探测定理:若 p 为奇素数,x21(modp) 当且仅当 x=1,p1

选取一个质数 px 测试:x=px 为质数;x=kp(k>1),合数;px1%x1,合数;这些都是常规操作,接下来使用二次探测。令 k=x1,只要 k 为偶数就重复操作:将 k 除以 2,记 t=pk%x,若 t1,p1x 非素数;若 t=p1,无法继续套用二次探测定理,结束。选取大约 10p 进行上述过程。

使用 MillerRabin 素数检测 写完后最好测验一下其准确性,避免奇葩错误。

P4688 [Ynoi2016] 掉进兔子洞

对于三个区间分别用 bitset 表示其中数值出现的情况(用莫队处理),然后数 A&B&C 里的 1 的个数就可以得出答案。因为有重复出现的数字,离散化的时候不要 unique,让每个数第一次出现为 x,再出现为 x+1,x+2

如果直接一遍莫队并存储信息,空间消耗为 nmw,不太够,可以把询问分成若干组处理。

P5355 [Ynoi2017] 由乃的玉米田

使用莫队处理。

对于加减法,用 bitset 维护每个数的存在性,然后左移、右移、按位与就可以判断了。(判断加法需同时维护 v,maxv 的存在性 )

对于乘法,暴力枚举 v 的因数分解即可。

对于除法,若 vmx,只有 mx 种可能,同样可以暴力;若 v<mx,不用莫队了,把每种 v 的询问拿出来处理一遍(记录每个位置的上一个与其匹配的位置)。

P4689 [Ynoi2016] 这是我自己的发明

不管如何换根,一棵子树的 dfs 序区间可表示为原树上的两段区间。于是询问就被转化成:从 dfs 序的两段区间中选出两个相同的数,记作 f(l1,r1,l2,r2)。每个询问有四个变量,不好搞。把它差分成前缀的形式,只需要计算若干 f(1,r1,1,r2),用莫队处理。

P5304 [GXOI/GZOI2019]旅行者

如果把这 k 个点分成 A,B 两组,以 A 为起点跑一遍多源最短路,就求出了 AB 的最小答案。那么如果进行若干次划分,对于 x,y,都在某一次被划到了不同的两组,最终答案就求出来了。枚举二进制位,按照这一位为 0/1 分成两组计算,这样的划分显然是符合要求的,并且只有 logn 次。

LOJ#6485. LJJ 学二项式定理

单位根反演:[k|n]=1kk1i=0ωnik。证明:k|n 时右边是 1k×kk|n,用等比数列公式得到右边为 0

枚举 %4 余数 k,得到: 3k=0akni=0Cinsi[4|(ik)]

把后面的用反演带入:143k=0akni=0Cinsi3j=0ωj(ik)4

改变枚举顺序,并把 w4 的质数拆开,得到:143k=0ak3j=0ωjk4ni=0Cinsi×ωij4

后面那个可用二项式定理化简,得到:143k=0ak3j=0ωjk4(sωj4+1)n。可以用快速幂求了。

取模意义下的单位根:wk=pow(g,mod1k),其中 g 为原根。

10.22

P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III

n 分为一块,先预处理 fi,j 表示块 [i,j] 内的答案,复杂度 O(nn)。对于询问,中间整块的答案 ans=fx,y 已经有了,还要考虑两边零散的 n 个数。

对于每种数开个 vector 记录其出现位置,然后对 n 种数判断区间里是否有 ans+1 个,如果有就 ans+=1,并继续判断。因为 ans 至多增加 n,所以单次复杂度 O(n)

P5305 [GXOI/GZOI2019]旧词

如果把指数 k 去掉,就是P4211path(root,x),path(root,y) 的重合部分是 path(root,lca(x,y))。树链剖分,先对 path(root,x) 路径 +1,再询问 path(root,y) 的和就是 depth(lca(x,y))。利用这一思想就可以解决 P4211

本题加上了指数 k,只要修改每个点的贡献:原本每个点的权值为 1,现在把深度为 d 的点的权值差分,赋为 dkdk1,就可以一样做了。

10.24

P4364 [九省联考2018]IIIDX

题意就是给出一棵树(结构有特殊性质),x,valxvalfax,而 vald 的排列,求 val 的最大字典序。

直接贪心,依次考虑编号从小到大的点 x,设其子树大小为 szx,那么选 valx 的时候显然要留出 szx1 的空位,还要给同一层的 y<x 的子树也留出 szy1 的空位。用线段树维护当前每个数的排名(把预留的去掉),求 valx 就是在线段树上二分,若有相同值 valx 要选最右边的。

然而这题还是有些奇怪的(成为黑题的原因吧),说不太清楚。差不多是这么个意思。

P3160 [CQOI2012]局部极小值

局部极小值的四周没有局部极小值,那么最多 n2×m2=8 个极小值,可以状压。从小到大填入每个数,fi,j 表示填了数字 [1,j],局部极小值填充的状态为 j 的方案数。每个极小值必须先于周围空格填入,按照这个枚举转移即可。

现在保证了是极小值的位置都是极小值,但没有保证不是极小值的位置一定不是极小值。所以爆搜得出每种可能的极小值局面,然后容斥。

P4292 [WC2010]重建计划

先用分数规划(二分答案)转化为判定性问题,然后使用点分治。计算跨过 x 的链的答案:用“滑动窗口”(单调队列)把子树合并起来,每次的复杂度为当前子树最深深度加上之前子树的最深深度,所以要按最深深度排序,从小到大处理。

知耻而后勇。最后的机会了,NOIP冲冲冲!!!

10.25

BZOJ4762 最小集合

f(S)=aSa, S/a 表示从集合 S 里拿掉元素 a。按照题意写出答案为 S[f(S)=0][aS,f(S/a)0]。比较麻烦的是 的条件不好记录。

把后面的部分容斥,得到 S[f(S)=0]SS[aS,f(S/a)=0](1)|S|

0 变成了 =0,于是条件可以写成 [(aSf(S/a))=0],这个东西就可以放在 dp 状态里了。

fi,j,k 表示处理了 i 个数,j=f(S)k=aSf(S/a)(1)|S| 的和。分类转移就好了。

复杂度为 O(n×310)

10.26

P7520 [省选联考 2021 A 卷] 支配

1、若 x 支配 yy 支配 z,则 x 支配 z

2、若 x,y 都支配 z,则 x,y 之间也存在支配关系

3、对于 x,设 Dx 为其支配集。根据第2条,Dx 中有且仅有一个 y 满足 Dx 中除了 x 都支配 y,连边 (fax=y,x),最终会构成支配树。

4、这个 y 就是支配集最大的那个点,于是可以暴力构建。

5、加入一条边,Dx 变化,要么 Dfax 变化,fax 不再支配 x

6、加入边 (u,v),若 fax 不再支配 x,则删除 fax 后,1 可达 uv 可达 x

7、具体地,删除每个点后爆搜一遍,得出所有 Dx,然后按照4构建支配树,复杂度 O(n2)。预处理6所需的信息,每次询问为 O(n)。总复杂度 O(n(n+q))

P7516 [省选联考 2021 A/B 卷] 图函数

对于 f(u,G),若 v1 的贡献,则 uv,vu 都存在不经过 v 的点的路径。

一种做法就是用 floyd O(n3) 算出 du,v 表示 uv 不经过 u 的最大路。“最大路”定义为经过的边中最小编号最大的路径(最多删掉几条边后还存在)。然后答案就很好算了。得分44——100。循环的时候注意上下界,可以使用指针卡常。

还有一种是先枚举 u,然后把边倒着加进去(正图反图都要处理),加入 (u,v),若都没被标记,先留着;若有一个被标记,就从这个点出发搜索。每个点最多经过一次,复杂度 O(n(n+m))。还可以换用 bitset,复杂度 O(n3w)

P7519 [省选联考 2021 A/B 卷] 滚榜

两个条件:总分单调,封榜后做题数单调。先让所有人的总分都变成最大值(预先计算费用),强行满足第一个条件。若顺序确定,之后每次操作都是让后缀 +1(保持第一个条件满足),去满足第二个条件。直接 dp,令 fi,j,k 表示已经处理的集合为 i,最后一个人是 j,还剩 k 次过题数的答案。暴力转移就好了,复杂度 O(2nn2m)。如果使用一些枚举技巧是跑不满的。

已经发榜的人还要和未发榜的人比较,所以初始化要注意一下。

P7515 [省选联考 2021 A 卷] 矩阵游戏

先随便构造出一组 a,然后进行调整。给 a 的第 i+xi,xi,+xi,xi,第 j+yj,yj,+yj,yj,并不改变 b。可以列出若干关于 x,y 的不等式。调整一下就都变成了作差的形式,使用差分约束求解。

AT4439 [AGC028E] High Elements

依次考虑每一位,是否可以填 0。需要判断若当前位填 0 后面是否可行。

称原本序列中的前缀最大值为“旧最大值”,其余的为”新最大值“。结论:若有解,一定可以让其中一个序列只有”旧最大值“。证明:若两个序列都有”新最大值“ x,y,那么交换 x,y,之后 x,y 就都被”遮住了“,而两个序列的前缀最大值个数仍相等。

于是考虑判断能否构造出其中一个序列只有”旧最大值“的方案。设 A 只有”旧最大值“, 另一个序列为 B。当前 A,B 前缀最大值的数量为 ca,cb,之后还没动的”旧最大值“数量为 cB 之后的”新/旧最大值“数量分别为 p,q,则需要满足条件 ca+cq=cb+p+q2q+p=ca+ccb

等式右边是定值。左边的 2q+p,可以转换成”带权上升序列“:让”旧最大值“价值为 2,”新最大值“为 1,在后面是否能找出一个权值为 ca+ccb 的上升序列。发现总价值由若干 1,2 组成,那么若 x 可达,x2 必可达,所以只要分别计算总和为奇数/偶数的最大上升序列。可用线段树维护。

上述过程基于”A中只有旧最大值“的假设,而这个假设也的确成立:对于后面任意一个非”旧最大值“的位置 x,若 x 被塞到 A 中成了”新最大值“,说明能遮住 x 的已经在 B 里,那么不妨把 x 扔到 B 里,并不会增加 B 的前缀最大值数量。

10.27

CF1601C Optimal Insertion

b 排序,显然若 i<jbi 插在 bj 左边更优。所以 b 之间没有逆序对,只要考虑 a,b 之间的逆序对。然后又发现 bj 插入的最优决策点也一定在 bi 右边。

一种方法是从左往右逐个插入,用线段树维护每个位置的答案。但这样比较烦,比较慢,还容易错。使用分治,每次算出 bmid 的最优决策点,然后往两边递归。这样计算最优决策点的时候可以直接暴力扫,不需要数据结构维护。

CF1601D Difficult Mountain

结论:将所有人按 max(s,a) 排序,依次考虑,能爬就爬,这样的方案最优。

证明比较麻烦。分类讨论?可能可以考虑交换两个人后的变化来证明。

P3270 [JLOI2016]成绩比较

总方案数可以拆成人员分配和成绩分配两部分。

人员分配(被碾压的是哪些人?第 i 门课被超过的是哪些人?):对第一个问题容斥,第二个直接算。设 f(x) 表示定了 x 个人被碾压,每门课被 1 超过的人员分配方案数,不难得到:f(x)=(n1x)×mi=1(n1xRi1),容斥一下就是人员分配方案数 num=n1i=k(1)ik×(ik)×fi。这里有一个 (ik) 别忘了,因为每种“至少碾压 i 个人”对应 (ik) 个“至少碾压 k 个人”。

还要考虑成绩的分配。这个很好写,枚举第一个学生第 i 门课的成绩 j 得到 g(i)=Uij=1jnRi×(Uij)Ri1。但 Ui 的范围为 109,需要优化。jnRi×(Uij)Ri1 是关于 jn1 次项,套上 后成了关于 Uin 次多项式。算出前 n+1 个值后使用拉格朗日插值算出 g(i)

最终答案只需将二者相乘,即 num×g(i)

10.28

CF1601E Phys Ed Online

li%k 相同的询问放在一起处理,问题就成了:给定 l,r,求 ri=l(mina[l,i])

fi=nj=i(mina[i,j])nxti=minj>i,aj<ai{j},有递推式 fi=fnxti+ai×(nxtii)

对于询问 l,r,令 p[l,r]a 最小的位置,有 ans=flfp+ap×(rp+1)

复杂度 O(nlogn)

P6669 [清华集训2016] 组合数问题

Lucas 定理:(nm)(m/pn/p)×(m%pn%p)(modp)。观察发现,若把 i,j 都写成 k 进制数,当且仅当出现某一位 i<j(ij)0(modp)p|(ij)

数位 dp,在状态里记录 i,j 的相对关系、injm 的大小关系,暴力转移。

P5933 [清华集训2012]串珠子

fs 表示使集合 s 连通的方案数,直接转移容易出现重复。考虑计算反面:使 s 不连通的方案数 gs.然后用总方案去减。计算 gs 时选一个点为特殊点,枚举与特殊点连通的集合 t,有 gs=ft×gst。复杂度 O(3n)。使用子集卷积和多项式科技可优化至 O(n22n)

10.30

CF1598G The Sum of Good Numbers

以下结论均基于“a,b,x 中不出现 0” 的条件。

ab,必有 |a|=|x||a|=|x|1

1、|a|=|x|1,必有 |b|=|x|1,只有 n 种。

2、|a|=|x|,此时需先求出二者的 lcp,然后和情况 1 类似,也只有 n 种。

总共可能的结果只有 2n 种,然后拿哈希 check 一下是否可行。

10.31

CF1569F Palindromic Hamiltonian Path

看着高级,实际上是个暴力题。只需要知道哪些点同色时合法,乘上组合数就是答案。也就是求颜色的划分,总状态数为贝尔数,约为 105

初始状态是两两配对的情况,可以直接暴力搜索,复杂度 12×11×10×9×8×7。然后枚举哪两个并在一起转移。

11.01

CF1555F Good Graph

每条边最多属于一个环,否则这两个环拼在一起异或值为 0。动态加边的构成先离线建出生成树。然后对于每次询问,判断这条链上的边是否都没被覆盖、异或值是否为 0。第二个条件容易判断,第一个条件直接在 dfs 序上用树状数组暴力修改(差分,前缀和),反正每条边只被覆盖一次。

CF1535F String Distance

先把所有字符串排序,然后算出相邻两个字符串的 lcp 长度 Li。字符串 i,jlcp 就是 L 在区间 [i,j] 内的最小值。这部分复杂度为一个 log

发现答案只能是 1,2,1337 三种,1337 的容易解决。只要算出答案为 1 的答案就出来了。若 f(x,y)=1 ,除去一段后缀一段前缀,中间部分 x 有序。

方案一:预处理后直接暴力可以弄到 n2。考虑另一种做法,先枚举 x,然后枚举两个切割点,左边一段右边一段哈希后统计一下,答案就可以算了,设 S=|si|×n2×105。复杂度 n×(Sn)2=S2n(直接 map 会再带一个 log)。根据 n 的数值选取不同的做法,复杂度为 min(n2,S2n)S43

方案二:枚举 x,根据 lcp(y,x) 的单调性用单调栈维护 lcp(y,x) 相同(=s)的 O(m) 段区间。对每段区间分别搞:算出从 s+1 开始的 sx 的极长有序区间 [s+1,t],要统计 [t+1,|sx|] 这一段与 x 相同的 y 的数量。把所有串反插入 trie 树,然后二分。

P5955 [POI2018] Pionek

只有在答案向量上投影为正的向量会产生贡献。将向量极角排序后,枚举答案向量极角 x,贡献为正的区间随 x 变化单调,双指针处理。

10.02

Codechef Maximum GCD

暴力做法:分类讨论,看看有没有选 a1,如果选了 a1,只需枚举另一个;否则枚举 a1 的约数看看能否成为答案。可以拿到 60 分。

一个乱搞:先把 a 排序去重,每种数至多留 3 个,然后讨论有没有选前 60 个,如果选了做法不变;如果没选,这时候只要枚举 a[1,60]gcd 的约数。很可惜,最后一个 subtask 有一个点无法通过。不选前 60 个了,随机选 60 个,还是过不了。猜测这个点大概形如 k,2k,3k,4k,nk,k1e13,可以先把所有数的 gcd 除掉再处理,不知道能不能过。反正如果不是 ACM,这个乱搞应该可以拿不少分。

正确做法:选择的这个 i (i<j) 满足 sisi1,其中 si 为前缀异或和。这样的 i 不超过 log1018 个,对每个暴力就好了。如果要更快一些,有用的 j 也只有 log1018 个...

证明:反证,若 si=si1,还要用 i,答案 x|sisi|ai,si|ai1,那么用 i1 的效果是一样的。

本文作者:-敲键盘的猫-

本文链接:https://www.cnblogs.com/whx666/p/15333567.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   -敲键盘的猫-  阅读(36)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起