record 3.25-3.30

~ mx noi r3 B

我们发现,操作 \(1,3,4\) 都可以用树链剖分+线段树解决,但是操作 \(2\) 并不行。这是由于你打的 tag 并没有交换律,所以不能在另外一个点分树上进行操作。

那我们就要保证这个 tag 的相对顺序不发生改变,最简单的办法是我们都在线段树上操作就好了。

注意到 \(k\) 很小。

你考虑一次 \(u,k\) 的操作 \(2\),我们枚举 \(v\)\(u\)\(lca\),然后你去定位到 \(lca\) 去除 \(u\) 这个子树所在的两个区间,我们相当于是对这两个子树的 \(dep=dep_{lca}+x\) 的位置进行一个修改。

那你就考虑每个区间记 \(k\) 个 tag,表示这个区间的 \(dep=mndep+i\) 位置打了什么 tag,下传标记都是容易的。

总复杂度 \(O(nk\log^2n)\)

arc175 C

我们第一反应可能是一个类似于凸函数 slope trick 之类的东西。那么我们设 \(f_i(x)\) 表示 \(a_i=x\) 时仅考虑前 \(i\) 个位置的最小值。

但是你稍微手玩一下发现不太对劲。具体来说,如果两个相邻区间有相交的话,我们似乎可以证明,一定存在一个值最小的解,使得这两个区间的取值相同,也就是说,这两个区间可以简化为一个区间。事实上这是正确的,我们可以分讨证明。

那现在任意两个相邻区间都不会相交了,我们考虑现在仍然相邻的 \(x-1,x,x+1\) 三个区间,如果它们的相对位置是 \(x-1,x,x+1\),你发现 \(x\) 的取值无关紧要;如果是 \(x,x-1,x+1\),你发现 \(x\) 肯定要取最大值。

这样,我们可以确定每个合并之后的区间的取值,接下来就是从前到后考虑字典序最小。

你考虑前面最后一个数是 \(a\),现在考虑的这个合并之后的整体取值是 \(b\)。只要相邻几个位置的贡献之和不变,我们可以任意改变。稍微讨论一下就可以了。

当然这个做法还是有点麻烦。sol 里给了一个做法。说是我们从后往前考虑每个函数,你发现函数取到最小值的位置是一个区间。如果再往前一个区间跟这个区间有交就会合并为交,如果无交,根据大小关系分类讨论就是一个单点。然后从前到后确定取值就可以了。

arc175 D

我先想给定 P,在树上怎么做,这显然是个普通 dp。然后你发现由于我们可以任选排列,所以这个大小关系只要不产生矛盾我们就可以任意钦定,也就是说,唯一的限制是类似于两条链相交的部分大小关系必须一致。这东西不是很好,想了我一年,我觉得可能是要换一种 dp 方式。

然后我想了想链上怎么做,你经过一些思考之后发现你可以构造出 \([n,\frac{n(n+1)}2]\) 之内的任意解。这个时候其实已经有眉目了。

我们猜测对于树上问题,我们照样可以构造出 \([mn,mx]\) 之内的任意解。其中 \(mn=n\)\(mx\) 需要你根据树的结构简单算一下。

然后我开始想构造,发现不会做。

但是进一步地,我们可以考虑每个节点 \(u\) 的 dp 值 \(f_u\),你发现唯一需要满足的条件是 \(f_{fa_u}\le f_u\le f_{fa_u}+1\),也就是说,我们声称只要满足这个条件,我们总能构造出一棵树的 \(f\) 是这个 \(f\)

具体来说,如果 \(f_u=f_{fa_u}\),我们令 \(a_u\) 比这条链上的最小值还小;否则我们干脆让 \(a_u\) 比最大值还大。

因为我们可以任选排列,所以这样的数总是存在,我们可以构造出来。

问题变成怎么求出一组 \(f\),使得 \(\sum f_u=k\),你发现对于一个点 \(u\) 进行 \(+1\) 之后,相当于要求它的子树全都要 \(+1\)。那么我们按照 sz 大小考虑每个点,然后贪心地取是不是就行了。

这个没问题,我们可以贪心证明,因为 \(mx_u=\sum mx_v+sz_u\),所以就证完了。

? mx noi r3 A

我们发现一个 \(a\) 操作 \(n\) 次之后得到的是 \(2^n(a-n)\)。我们简单算一下 \(\Delta\) 发现 \(f_n-f_{n-1}=2^{n-1}(a-(n+1))\),这说明 \(f_a=f_{a-1}>f_{a-2}>\dots>f_0\)

首先我们要会判定一个给定 \(a\) 是否合法,你发现很简单就是从前往后贪心,我们每次操作这个位置的数让它比上个数大的前提下最小就行了。

我们可以先求出一个 \(g_x\) 表示能通过若干次操作到达 \(x\) 的数当中,最小的那个是多少。然后简单推导过后发现如果 \(x=2^{\alpha}\beta\),那么 \(g_x=\alpha+\beta\)。这东西一看就有点用。

然后你假设 \(a\) 序列操作过后得到 \(b\),那么你现在就是要求出一个长度为 \(n\) 的递增的 \(b\) 出来,\(\text{minimize}\sum g_{b_i}\)

这不就是给你一个序列,让你从中取出 \(n\) 个数,使得总和最小。我们显然每次贪心取最小值就可以了。

那么 \(g_x=\alpha+\beta=t\) 的数有多少个呢?这需要分奇偶性讨论,因为 \(\beta\) 必须是奇数。

如果 \(t\) 是奇数,那么 \(\alpha\) 是偶数,这样的数形如 \(2^{2k}+t-2k\) 的形式,一共有 \(\frac{t+1}{2}\) 个。

如果 \(t\) 是偶数,那么 \(\alpha\) 是奇数,这样的数形如 \(2^{2k-1}+t-2k+1\) 的形式,一共有 \(\frac t2\) 个。

这样我们就做完了。

啊不还没做完。

我们考虑如何找到位置 \(x\) 的值,一个初步想法就是发现我们当前会做给定一个 \(2^{\alpha}\beta\) 和一个 \(lim\),问 \(x\le 2^{\alpha}\beta,g_x\le lim\) 有多少个。我们会在 \(O(\log)\) 时间内做。

那我们就可以考虑开始二分了。先二分出一个 \([2^t,2^{t+1})\),这相当于找到了答案一个粗略的界。然后在这个范围内,我们枚举一个 \(\alpha\),然后二分一个 \(\beta\),复杂度大约是 2~3 log。

唉唉 spx 给了个找规律的神秘做法。

就是你对这个 \(b\) 数组找规律,为了方便,我们先假设我们的 \(lim\) 是整的。

你发现这个 \(b\) 的差分数组,是前面一些 \(1\),后面一些 \(2,4,8,16,32,\dots\),并且 \(1\) 的个数是跟 \(lim\) 相关的,\(2,8,32,\dots\) 的个数成递减的等差数列,\(4,16,\dots\) 也是类似。

然后你考虑我们给你一个 \(x\),你先去定位它在哪一段里头,这个应该是不难做的。然后你再算它是谁,这个也是不难做的。

接下来我们考虑 \(lim\) 不是整的的情况。

据 spx 所说,根据 \(lim\) 的奇偶性,我们每次插入都是在奇数段后面插一个数,或者偶数段后面插一个数。总之大概还是能做的。

唉唉怎么加训找规律啊。

额题解做法好像也很厉害。

QOJ 5070

我们有一些简单的思考。

第一个思考是,对于一个空行,我们肯定可以交替填 01,然后把整个问题划分成独立的问题。事实上,我们是对于所有不矛盾的行列都可以这么做,事实上我们可以对不矛盾的每一段都这么做,总之可以填出来一些问号。

第二个思考是,我们可以先 chk 每个填了四个的地方是不是合法,然后把填了三个的地方能填的都先填出来。这样填完之后,剩下的还有可能非法的正方形里,就只剩填了 \(0,1,2\) 三种情况。

上述两个思考并不矛盾,可以同时使用。

我们做第二个,然后是不是随便填就是对的?

看了 sol,真是这啊?为啥对啊?

这证了个啥?

我们来这么说吧。现在是所有仍可能非法的正方形,填了 \(0,1,2\) 这三种情况。我们声称:如果当前局面存在一个解,那么我们将其中任意一个问号所填的数进行翻转之后仍然有解。

这种东西是不是应该考虑归纳证明。

呃呃有点麻烦,不过 luogu 题解好像说的有点道理。

就是说我们考虑你瞎填了一个数之后引起了一些更新,我们尝试证明这些更新不会产生矛盾。

你发现更新一定是由于你包含新填的这个位置的四个方形其中有填了两个的,然后你经过一些考虑,发现它们最多朝着四个互相独立的方向独自延伸(这是由于你填了一个数之后,就直接造成了三个方形的合法,只需要考虑一个方向的方形是否合法)。然后这个显然是不会造成矛盾的。

~! QOJ 850

编辑距离,好像是典题,但是我没做过。

首先我们知道 insert 和 delete 的差值是固定的,那是不是我们并不会使用多余的 insert 和 del 呢。

不一定,因为一个 ins 跟 del 能形成一个 shift,这是 replace 做起来麻烦的。

我们现在当然可以 \(dp_{i,j}\) 但这没啥用。观察到 \(k\) 很小。

我们是不是可以这样,你记 \(dp_{i,k}\) 表示 \(s\) 的前 \(i\) 个位置,使用 \(k\) 次操作,最多能匹配到 \(t\) 的什么地方。

你别急,这东西不一定对呢。

我们发现相当于是在空间中有若干个 \((i,j,k)\),表示 \(s_i,t_j\)\(k\) 次操作可以进行匹配。

你发现 \((i,j,k)\) 可以生成 \((i,j+1,k+1),(i+1,j,k+1),(i+1,j+1,k+1)\) 以及当 \(s_{i+1}=t_{j+1}\) 时可以生成 \((i+1,j+1,k)\)

这看起来像一个 \((0,0,0)\to(n,m,*)\),其实是 \((0,0)\to(n,m)\),只能向右、上、右上走,然后每个位置有 \(01\) 的权值。

那我们关心的是有没有一个 \(\le k\) 的解,所以我们是不是可以考虑不使用 \(k\) 的段,这样的段只有 \(O(k)\) 个。

看了一点 tip。

我们发现 \(|i-j|\le k\),因此直接做 dp 可以得到一个 \(O(nk)\) 的做法。

进一步,我们观察到 \((i,j,k),(i',j',k')\)\(i-j=i'-j',k=k',i>i'\) 时,\((i',j',k')\) 是没用的。

那我们就可以 dp 了。你设 \(dp_{i,j}\) 表示 \(k=i,i-j=j\) 的时候,\(i\) 的最大值,然后事实上你没有损失信息,所以可以一样做 dp。

现在我还要会一个给 \(i,j\),问 \(s_{i,i+x}=t_{j,j+x}\) 最大的 \(x\)。咋说呢,hash 得了。

~ QOJ 6366

每个字母最后保留下来的是一个区间。

有一个比较显然的 dp,是 \(dp_{i,j}\) 表示我们匹配到 \((i,j)\) 时的最小代价,然后转移考虑如果 \(s_{i+1}\)\(t_1\sim t_j\) 中出现过,那么就必须跟 \(t_{j+1}\) 匹配,否则可以选择先不匹配。这样复杂度是 \(O(n^2)\)

但是我们仔细分析,你发现上面这个东西的有用状态数其实只有 \(O(n)\),具体来说,我们把每个字符在 \(t\) 中第一次出现提取出来作为关键位置,只有这些关键位置的 dp 值是有用的,并且还要要求 \(s_i=t_j\),所以总共是 \(O(n)\) 的。感觉做法应该要利用这些性质。

或者我们可以考虑,你一旦确定下 \(t_1\) 要跟谁匹配之后,你把两个字符串都按照 \(t_1\) 作为分隔符进行分割,发现事实上你把这个问题分成了若干个小问题。

上面说的有一点问题,如果 \(s_{i+1}\)\(t_1\sim t_j\) 中出现过,并且后面还有它的至少一次出现,那么它必须匹配。

或者说,一个字符处于必须匹配的状态,当且仅当这个字符在 \(t\) 中出现次数在 \((1,cnt_c]\) 当中。

那如果我们把每个字符的第一次、最后一次出现提取出来,这样相当于在同一段当中,哪些字母必须匹配,哪些字母必须跳过都是我们清楚的。

我们可以对每个段跑一次 kmp 匹配一下,这样我们就知道匹配之后应该跑到哪里去。

那这样我们就做完了。复杂度 \(O(|\Sigma|n)\)

*? arc127 F

这啥数论题啊,我一点不会。大概扫了一遍 sol,我们看看能不能自己整一个出来。

首先第一个感觉是你 \(m\) 比较大的时候我们应该是都能取到的。考虑说明这一点,我们先把 \([0,m]\) 变成模 \(b\) 的剩余系,相当于是在 \([0,b)\) 上跑 \(\pm a\),那我们给一个 \(a+b\le m+1\) 时的构造。具体来说,我们设当前的位置为 \(x\),当 \(x\ge b\) 时我们不断 \(-b\),使得 \(x\in[0,b)\),然后这时 \(+a\)\(x\in[a,a+b)\),这是一个合法的操作,并且我们成功跳到了模 \(b\) 的另一个剩余系内。不断进行这样的操作就可以走到所有位置。

然后我们要考虑 \(a+b\ge m+2\) 的情况。

我们仍然在 \([0,b)\) 上考虑,但是这时我们不能跳到所有的位置。你直观感受一下,好像我们能跳到的位置也只有你每次跳 \(b\) 的时候跳到最大/小,然后去 \(+a/-a\)

问题是我们是否会在中途更换。也就是说我们本来是跳 \(b\) 跳最小,然后 \(+a\),有没有可能某一次改成跳 \(b\) 跳最大,然后 \(-a\)

你发现没可能,因为你 \(+a\) 之后无法支持你再去 \(+b\)

那我们有没有可能跳到同一个点上,我们考虑取总共需要步数最少的那个,如果这样的话说明出现了 \(ax+by=0,x,y\neq 0\),这要求 \(|x|+|y|\ge a+b\),这说明至少要有 \(a+b\) 个点,但我们没有。所以不会有环。

那我们只需要分别求出来这两种操作可以到多少个点就可以了。

相当于求一个 \(k\),使得 \((v+ka)\bmod b+a>m\)

啊后面不想看了,之后再说吧。

mx 3.28 D

你考虑我们对一组生成好的 \(S\) 找一个“基底”,使得对这个基底不断进行 or 操作就可以生成 \(S\)

我们可以把 \(S\) 中任意一个能被其它东西 or 起来得到的给删掉,一直删下去,现在,我们得到了一个任意一堆东西 or 起来都不等于其他人的东西。

进一步,我们发现,两个基底 \(a,b\) 如果 \(a\& b\neq 0\),那么就会生成一个 \(a\& b\) 也作为基底。所以我们的基底满足一个树形结构。以 \(0\) 作为根节点。

然后你发现一棵树的方案数是 \(dp_u=\prod_v(dp_v+1)\),唯一需要满足的限制条件是节点个数不超过 \(n+1\)

那因为题目告诉我们有解,所以我们可以算一算 \(f_u\) 表示答案是 \(u\) 的树最少用几个点,这部分肯定随便做就好了。

我现在有点好奇怎么证肯定有解。

额这个基底是假的,这个东西连出来不一定是个树啊。所以现在我这个构造方法能不能构出来也不好说。

但是 spx 说了一个构造方法,就是我们取出 \(a_1,a_2,\dots,a_k\) 个二进制位,然后除去空集和全集,先造出 \(2^{a_1}-1\) 种用 \(a_1\) 位的,然后剩下的所有构造这 \(a_1\) 位都是全 \(1\),然后再造 \(2^{a_2}\) 个,这样我们可以对 \(m\) 进行一个二进制拆分就可以给一个构造。这样的问题是,对于一些小的情况不一定能给出构造。

额但是 sol 给的构造方法,它是把大的问题搞到小的问题上,然后对小的问题我们自己手动构造。

upd:看到有人写的应该是我的做法,那说明我没问题。

*! mx 3.28 C

这个题很厉害吧。

首先我们有一个状压,\(O(n2^n)\)。这解决了 \(n\le 26\) 的情况。

接下来我们要考虑一点别的东西。一个较为好的想法,是我们考虑一下树的情况,如果树会做了,因为我们每次走的都是某个生成树,所以我们可以枚举树就会做了。

那我们想想树,你会想出一个跟连通块个数有关的 dp,这个很没用。

你会想一些贪心,但是感觉都不对。

我们先看看序列上怎么做吧,就是没有取的顺序的限制,随便取。

肯定是所有正贡献在负贡献之前。正贡献,肯定是按照扣血量从小到大取。负贡献,事实上经过尝试发现是按照加血量(不是净加血量)从大到小取。这个确实可以证明,但是没有那么好想。

好,我们现在有一个最优取值顺序,这个顺序能说明什么呢?你考虑第一个数,当它的父亲被取出之后,它立刻会被取出(因为取其它的都不优)。

这个是不是等价于你把顺序标在点上,然后在树上贪心。

这种贪心可以这样做,是因为对于任意一个当前状态 \(S\)\(x,y\) 两个选择,总是一个比另一个优,不会存在两个状态 \(S,S'\) 使得 \(S\) 情况下 \(x\) 优而 \(S'\)\(y\) 优。

posted @ 2024-04-01 07:09  PYD1  阅读(9)  评论(0)    收藏  举报