2025全停课第1周做题记录+考试记录

周一杂题(6.23)

rsxc

首先看到异或就要想线性基,然后我们先考虑如何判断一个区间的好坏。有充要条件:设线性基内元素有 \(x\) 个,那么区间内有 \(2^x\) 中不同的数。

我们可以先预处理好的区间。考虑扫描线扫 \(r\),于是我们维护前缀线性基。若将 \(pos\) 倒着排序那么 \(l\)\([pos_{k+1}+1,pos_k]\) 中的线性基恰有 \(k\) 种元素。我们还需要判断 \(2^k\),于是就记录一个数组表示 \([1,i]\) 中每种数从右往左出现的位置中第 \(2^k\) 大的值,这样就能找到合法的区间了:\(l\in[pos_{k+1}+1,lp_{i,k}]\)

假设我们求出每个二元组的合法区间 \([L_{i,k},R_{i,k}]\),考虑查询,写出式子:

\[\sum_{i=l}^r\sum_{k=0}^{\log i}\max(0,R_{i,k}-\max(L_{i,k},l)+1) \]

我们可以交换 \(\sum\),然后分讨后面的几个 \(\max\)。考虑 \(R_{i,k}\) 无限制于是直接记录前缀和,\(L_{i,k}\) 同样记录前缀和,但是考虑有的 \(L_{i,k}<l\) 于是我们还要找分界点,这个你直接扫一遍就行。

详见这篇题解

CF1100F

板子题不讲。

优秀的拆分

SA 经典套路!当我们遇到要做跟不同长度的 lcp/lcs 有关的东西时考虑先枚举 \(len\),然后在每个 \(k\times len,k\in \mathbb Z \wedge k\times len<=n\) 处打上标记。对于每个标记点分别去算答案,因为每个长度为 \(len\) 的 lcp/lcs 都会跨过一个标记点。然后我们对每个标记点讨论分界的情况,可以发现我们只用把前后缀做出来建好 st 表就能 \(O(1)\) 查询。对每个分界点稍微讨论一下,对于合法的区间直接区间加差分一下即可。

论战捆竹竿

大神题。感觉讲烂了,我以前也写过题解,于是讲我之前没写出代码的关键。其实最关键的在与同余最短路的处理。

考虑我们可以选择一个大于所有模数的数作为 dis 数组的大小,然后暴力就是直接转嘛大家都会,但是区间转区间好难啊怎么办?我们就考虑把区间的开头与区间切割,当成一个数的转移,然后后面整个区间就是与开头的公差相同就正常做了。注意松弛的时候其实是可以单调队列优化的。

树上查询

看似简单实际有点小难。

考虑每个 \(a_i=dep_{lca(i,i+1)}\) 做贡献时的极长区间,然后就是对询问区间找一个交集 \(\ge k\) 并且 a 尽量大的,分讨启动。

  1. \(l\le l'\le r'\le r\),直接扫描线扫右端点,但是有 k 的限制不好做怎么办?考虑倒序扫描线。
  2. \(r<r'\),考虑合法的 \(l'\)\([l,r-k+1]\) 中,扫描线扫 k 带一个线段树即可。
  3. \(l'<l\),同理。

周二 VP arc125(6.24)

A 是糖。

B 是一个神秘数学题,我们要统计合法二元组 \((x,y),x,y\le N\) 满足 \(x^2-y=k^2\)。考虑移项变成 \((x-k)(x+k)=y\),要求 \(\sum (x-k)\)。考虑 \(x-k\le x+k\) 于是用 \(O(\sqrt n)\) 枚举 \(x-k\) 计算即可。

C 是沟槽构造题,考虑字典序最小所以我们每次在每段后面只能填一个满足条件的最小的数,然后最后一段填下降序列即可。

D 是简单 dp 题,有点神似子序列自动机。考虑设 \(f_i\) 表示以 \(i\) 结尾的数量,显然有:

\[f_i=\sum_{j=las_{a_i}}^{i-1}f_j \]

这个直接 BIT 优化转移即可。

E 是模拟网络流不错题,考虑一眼最大流,套路转化成最小割,然后我们注意到有三类边,其中后两者都与右部点有关,所以我们对右部点进行考虑。首先因为中间的边与左部点无关,所以我们直接对左部点排序即可,然后我们就可以枚举割掉了几个左部点,然后在右边判断右部点是否会被割掉以及其贡献。贡献为 \(\min(k\times b_i,c_i)\),于是对右部点按照 \(c_i\over b_i\) 排序即可双指针统计完答案。

F 是多重背包。首先一眼二元生成函数:

\[\prod (xy^{d_i}+1) \]

然后要求项数。直接做就炸了,考虑寻找性质。首先你有 \(\sum deg_i=2n-2\),然后你可以丢掉一个 \(n\),这样不影响。

然后我们尝试手搓一些数据,考虑展开生成函数的式子观察,你会惊奇地发现:对于一个固定的 \(y^k\),其 \(x\) 头上的指数一定是一段连续的区间。

考虑证明:

\(d_i=deg_i-1\),满足 \(d_i=0\)\(i\) 的数量有 \(t\) 个,则等价于我去证明:\(r_i-l_i\le 2t\)。我们考虑对于一个合法的 \((x,y)\),一定有 \(-t\le y-x\le n-2\),并且将所有点的状态取反还有 \((n-x,n-2-y)\) 合法,于是又有 \(-t\le x-y-2\le n-2\)。解出 \(x,y\) 的关系有 \(y-t+2\le x\le y+t\),所以对于一个固定的 \(y\) 有:\(r_i-l_i\le 2t-2\le 2t\),得证。

有了这个之后你就可以跑一个多重背包了,设 \(f_{i,j}\) 表示考虑前 \(i\) 个点中所有 \(d=j\) 的答案。然后考虑不同的 \(d\) 只有 \(O(\sqrt n)\) 个,用单调队列优化即可做到 \(O(n\sqrt n)\)

周三 dp 专题复习(6.25)

宝物筛选

多重背包板子。放在这里主要是提醒自己其单调队列写法。

int n, V, f[N], g[N], q[N], v[N], w[N], m[N];
inline void Max(int &x, int y){if(x < y)x = y;}
signed main(){
    n = rd(), V = rd();
    for(int i = 1; i <= n; ++i)v[i] = rd(), w[i] = rd(), m[i] = rd();
    for(int i = 1; i <= n; ++i, memcpy(f, g, sizeof f))for(int j = 0; j < w[i]; ++j)for(int k = 0, hd = 1, tl = 0; k * w[i] + j <= V; ++k){
        while(hd <= tl and q[hd] + m[i] < k)++hd;
        if(hd <= tl)Max(g[k * w[i] + j], f[q[hd] * w[i] + j] + (k - q[hd]) * v[i]);
        while(hd <= tl and f[q[tl] * w[i] + j] - q[tl] * v[i] <= f[k * w[i] + j] - k * v[i])--tl;
        q[++tl] = k;
    }
    wt(f[V]);
    return 0;
}

合并饭团

有点思考量的区间 dp 题。你考虑第二种操作直接暴力枚举是 \(O(n^4)\) 的,但是其实双指针从两边扫就行了。

FAR-FarmCraft

考虑维护 \(f_u\) 表示做完 \(u\) 的子树的答案以及 \(g_u\) 表示跑完整个子树的时间。考虑 \(f_u-g_u\) 越小说明浪费的时间越少,于是在枚举子树的时候这种子树就越靠后去跑。然后就有做法了,我们按照 \(f_v-g_v\) 对子树排序然后更新答案即可,时间复杂度 \(O(n\log n)\)

Shopping

看到连通块想到淀粉质解决。考虑如果你选一颗子树肯定会选择根(废话),但是如果不选也有可能(废话 \(\times2\)),总之就是如果选就可以直接在 dfs 序上转,否则就不能动区间,所以转移不方便,于是考虑 dfs 序倒序转移 f。对第二种情况我们从 \(u+sz_u\) 转过来,否则就从 \(u+1\) 转即可。

苹果树

容易发现我们可以先选择一条链,并且一定是从根一直到叶子节点,不然还可以加长使其更优。然后我们在剩下的点中选择 \(k\) 个点。考虑这条链非常讨厌,它横在整棵树中间,让普通的树 dp 不好做。但是考虑它将这棵树一分为二,所以我们尝试去对于左边和右边的点做树上依赖性背包。我们设 \(f_{i,j,k}\) 表示到 \(i\) 这个点,选择了前 \(j\) 棵子树一共 \(k\) 个点(除掉链)的答案。

注意转移的时候我们不能将 \(i\) 中的苹果全部用掉,因为我们还要给链留一个,于是我们转移的 \(a_i\) 需要 -1。并且注意,因为我们记录的是前缀的信息,所以我们在做树 dp 的时候要将 \(f_u\) 的信息下传到 \(f_v\),并且我们实际写的时候可以省略第二维。对于剩下一半同理做即可。

基站选址

先写 dp 式子。设 \(f_{i,j}\) 表示在第 \(i\) 个村庄建第 \(j\) 个基站时前 \(i\) 个村庄的最小答案。注意因为我们的状态设计特殊,所以我们在最后多加入一个虚空村庄让其距离无限远,代价无限大但是建基站花费为 0 即可。写式子:

\[f_{i,j}=\min \{f_{k,j-1}+w(k,i)\} \]

容易发现第二维可扔掉,现在考虑做 \(w(k,i)\)。我们可以二分处理出一个村庄不需要代价的区间,把这些区间全部挂在右端点然后扫描线扫就可以处理相同 \(i\) 的所有 \(k\)。于是剩下就是区间加区间最小值所以线段树秒了。

周四 VP CF2089(THUPC 2025 决赛部分题)(6.26)

A

小构造题又废我 1h VP 时间。你考虑如果前面都是质数但是中间又不是后面又是看着会很奇怪而且感觉不优所以直接尽量前面一直填质数。首先第一个数必须是质数,然后依次考虑放 \(p-1,p+1,p-2,p+2\dots\) 即可。

B

B1(\(k=0\)

考虑到一个性质:若对于左端点 \(l\) 存在一个最小的合法区间 \([l,r]\),则满足 \(\sum_{i=l}^r a_i\le\sum_{i=l}^r b_i\)

推理证明:对于区间内一个位置 \(i\)\(a_i\) 首先会与 \(b_i\) 做减法,然后和 \(b_{i+1}\) 做减法,以此类推。所以 \(a_i\) 想要消掉就需要有一段 \(b\) 与之对应,但是考虑在 \(b_j\)\(a_i\) 做减法前 \(b_j\) 会和若干 \(a_k,k\in[i,j]\) 先做减法,所以就是上面的式子。

也可以考虑归纳证明,在此不详细展开。

然后考虑第二个性质:若对于左端点 \(l\) 对应的区间 \([l,r]\) 中有一点 \(i\),则 \(i\) 对应的区间 \([i,j]\) 满足 \(l\le i\le j\le r\)。证明简单。

现在考虑我们的答案:\(ans=\sum r-l+1\)。于是我们对于 \(i\) 线性扫出区间 \([i,j]\) 后则对于所有形如 \([l,r],i\le l\le r\le j\) 的区间都不会对答案做贡献。所以直接双指针扫过去即可。

B2(\(k\le2\times10^{14}\)

肯定二分答案。我们限制长度后去解决超出限制长度的区间,计算用的和与 k 比较。在处理的时候其实可以对每个位置暴力处理,考虑当一个位置 \(b_i=0\) 时这个位置就可以删掉了。于是用链表维护每个位置。然后考虑复杂度,因为每次操作相当于是辗转相减,所以是一只 \(\log\),然后还有二分答案的 \(\log\) 就是\(O(n\log^2n)\)

C

前置知识:一点古典概型知识。

困难题。注意到每个人均按照最优决策,所以在决策时我们需要去选择成功概率最大的。假设现在有 \(x\) 个锁,\(x+y\) 个钥匙。对于第一个人成功的概率为 \({x\over x(x+y)}={1\over x+y}\)。我们称第一个人选择的锁和钥匙为一号锁、钥匙,现在去考虑第二个人以及后面人的情况:

  • 选择一号锁和非一号钥匙。因为我们排除了一号钥匙所以还剩下 \(x+y-1\) 个钥匙,故成功的概率为 \(1\over x+y-1\)
  • 选择非一号锁和一号钥匙。成功的概率也为 \(1\over x+y-1\)。接下来考虑证明。

\(A,B,C\) 分别为第一个人拿到的钥匙为真的,第一个人失败,第二个人成功,下面有:

\[\begin{aligned} P(A|B)&={P(B|A)P(A)\over P(B)}\\&={{x-1\over x}\cdot{x\over x+y}\over{x+y-1\over x+y}}={x-1\over x+y-1}\\ P(C|B)&=P(A|B)P(C|AB)+P(\overline A|B)P(C|\overline AB)\\&={x-1\over x+y-1}\cdot{1\over x-1}+0={1\over x+y-1} \end{aligned} \]

证毕。

  • 选择非一号锁和非一号钥匙。成功的概率为 \((1-{1\over x+y-1}){1\over x+y-1}={x+y-2\over (x+y-1)^2}<{1\over x+y-1}\),所以不进行此种决策。

所以第二个人会选择与第一个人相同的锁或钥匙,并且选择锁或者钥匙的概率相同,所以第二个人会有 \({x-1\over 2x+y-2}\) 的概率选择锁,有 \(x+y-1\over 2x+y-2\) 的概率选择钥匙。并且如果第二个人选了锁,接下来的人就会一直选相同的锁直到锁开;否则就是一直选相同的钥匙直到发现其是假钥匙或者开了一把锁。因为这样他们的成功率比没有任何信息去瞎蒙的情况成功概率更高。并且我们可以计算第二个人成功的概率:\((1-{1\over x+y})\cdot{1\over x+y-1}={1\over x+y}\),和第一个人相同,以此类推可得到后面的成功概率同样为 \({1\over x+y}\)

也就是说除了第一个人外,我们对于相同的 \(x,y\) 都进行本质相同的操作(选相同的锁/钥匙),并且成功概率相同。这个问题我们尝试 dp 解决。设 \(f_{i,j,c}\) 表示现有 \(i\) 个锁 \(i+j\) 个钥匙,轮到了第 \(c\) 个人期望成功次数。

首先肯定从 \(x=1,y=0\) 的情况开始倒推(废话?)。我们进行一点小分讨进行转移:

  • 选择的是能够配对的锁或钥匙,有 \(f_{i,j,c}\leftarrow f_{i-1,j,c-l}\)。首先注意 \(c-l\) 是在模 \(n\) 意义下的,因为这 \(n\) 个人是轮着来的。然后我们要将锁和钥匙稍微分开处理,首先是因为选择相同锁或钥匙的概率不同,其次就是注意枚举的 \(l\) 的上界也不同。具体的,对于锁来说,因为最多就 \(i\) 把所以上界为 \(i\);对于钥匙上界就可以到 \(i+j\)。转移式就是:\(f_{i,j,c} = {\left((i-1)\sum f_{i-1,j,c-l}\right)+\left((i+j-1)\sum f_{i-1,j,c-l}\right)\over (i+j)(2i+j-2) }\)

  • 注意如果只选钥匙的时候我们还可以有 \(f_{i,j,c}\leftarrow f_{i,j-1,c-i}\),因为我们如果要发现这个钥匙是假的需要让 \(n\) 个人轮 \(i\) 次,每次选相同的这个假钥匙,所以有 \(f_{i,j,c}={j\over i+j}\cdot{i-1\over 2i+j-2}\cdot f_{i,j-1,c-i}\)。因为每次要选锁,所以还要乘选择锁的系数,然后那个 \({j\over i+j}\) 是选到假钥匙的概率。

  • 最后还要考虑的是这一次本身成功的贡献。考虑是固定一个相同的锁还是钥匙,直接拿成功的概率乘上每次选择的概率即可。

直接做时间复杂度 \(O(n^2LK)\),记得对于第一种情况进行前缀和优化,最后时间复杂度 \(O(nLK)\)

D

大分讨。我们先考虑什么情况下有解?因为每次操作是三个数为一组,所以我们可以把基本情况在草稿纸上列出来(在此不列出)。我们尝试总结一点神秘结论,比如若最后为一,只有 \(101\) 是无解的,其余均有解。还有就是连着两个一跟着什么东西好像也有解,但是 \(10010\) 这样也有解但是这又该怎么归类呢?

首先对于奇数位置为一且后面位置有偶数位置有一时一定有解。对于这种我们可以刻画成 \(??1??1?\) 的结构,现在我们尝试对此化简。看到一中间偶数个位置,考虑我们先随便操作,到最后还剩下两个位置的时候我们可以进行分类讨论。若现在为形如 \(1xy1\) 的结构,我们看 \(x=0/1\) 的做法:

  • \(x=0\),序列形如 \(10y1\)。我们可以这样操作:\(1(0?y:1)\),此时在遇到零后就与 \(y\) 无关了,现在简化成了 \(11\) 的情况。
  • \(x=1\),序列形如 \(11y1\)。我们可以这样操作:\((1?1:y)1\),此时同理可得 \(11\)

因此我们解决了中间间隔为偶数的情况,现在考虑形如 \(??11?\) 的做法。如果只有后面三个数我们肯定是直接做就对了,但是实际前面还有一段,所以我们希望维持最后这个结构。我们还是讨论一下:

  • 第一个为零,序列形如 \(0?11?\),我们先做最左边变成 \(11?\) 然后就行了。
  • 第一个为一,序列形如 \(1?11?\),这个可能没有那么一眼但是也不难,考虑先做中间的 \(?11\),因为无论条件最后都返回一,于是序列变成 \(11?\) 然后就又可以做了。

于是我们就解决完奇数位置为一且后面位置有偶数位置有一的情况。现在考虑最后一个位置为一的情况。因为我们已经做了前面一种情况所以不会出现一个奇数位置为一后面又有偶数位置为一。我们还是只看最后五个位置,这样不失一般性。现在开始大力讨论:

  • 序列形如 \(0?011\)\(01??1\)。这个就用上面相同的方法做就行了。

  • 序列形如 \(?0?01\)。我们继续去讨论第一个位置是多少:

    • 第一个为零,序列形如 \(00?01\),我们先做中间的 \(0?0\),但是我们不关心其取值,因为最后还有 \(0?1\) 一定为一。

    • 第一个为一,序列形如 \(10?01\),我们先做最前面的 \(10?\) 变成 \(0\),然后做 \(001\) 变成一即可。

然后你就发现貌似是讨论完了,对于长度为三的情况就暴力特判即可。

大概讲一下代码,首先你先特判长度为三的序列,直接分讨,然后注意每次合并你就当成维护并查集即可。把整个流程画出来你发现其实就是一个三叉树的形式,并且如果你从根开始 dfs 就行了。但是你这样做就不知道每次合并后相邻的位置的情况,所以你改装一下这棵树,加入链表的特征,让他能维护前后,每次合并同时维护链表即可。

E

小清新困难题。首先这玩意就是内向树拓扑序上抓一些点,但是要多一个限制,就是第 \(i\) 个位置需要小于等于 \(n-i+1\)。首先我们假设没有这个多的限制其实就是在树上跑一遍背包即可,做法显然。现在考虑限制二,这里有个妙手,就是我们考虑后缀最大值的限制一定是比限制二严格的,所以我们在 dp 中加一维去维护后缀最大,于是就有了 dp。设 \(f_{i,j,k}\) 表示从大到小考虑到了 \(i\),填了 \(j\) 个数,且最后这个数填在序列的位置 \(k\) 上。注意第三维的限制是强制填在一个地方,这样这个已有的序列中间是会有很多空位置的,这个用来给后面更小的数腾位置用。然后转移是简单的:

  • \(i\) 没被选,直接继承 \(f_{i+1}\) 的东西即可。
  • \(i\) 被选为后缀最大值,我们去枚举最后填在了哪里,注意枚举的范围是 \((k,n-i+1]\),于是有 \(f_{i,j,l}\leftarrow f_{i+1,j-1,k}\)
  • \(i\) 没有被选为后缀最大值,我们就需要考虑以 \(i\) 为根的子树怎么填。我们预处理出树上背包 \(g_{u,i}\) 表示在以 \(u\) 为根的子树中填 \(i\) 个的合法方案数。于是就可以转移了:\(f_{i,j+x,k}\leftarrow f_{i+sz_i,j,k}\times g_{i,x}\times{k-j\choose x}\)

最后注意一下边界即可,复时间杂度 \(O(n^4)\)

周五改前一天的 DE(6.27)

见上文。

周六周天(6.28,6.29)

做的题目不困难,于是没有准备写题解。

posted @ 2025-06-23 22:16  Lyrella  阅读(31)  评论(0)    收藏  举报