2023年12月随便做做

代码链接

2023.12.03

难绷了,ruarua 地厌学,救命。

Codeforces - 1086F - Forest Fires

(0)

以前的比赛原题,当时场切了。今天找到原题,觉得当时自己太牛逼了,反观现在自己真的是越学越菜。

2023.12.04

VP 了场 Edu,名副其实出题人〇神玩多了。

CF1902F - Trees and XOR Queries Again

(0)

线性基板题。不知道这场在干什么,就没一道好题吗?

2023.12.06

Codeforces - 1622F - Quadratic Set

(-3)

喔趣,好题。综合了不同的思路(主要是证明思路),切掉了这个题。

首先答案大于等于 \(n-3\)

\[\begin{aligned} &\prod_{i=1}^n i! = \prod_{i=1}^n i^{n-i+1} \\ &\Rightarrow \prod_{i=1}^{2k}i!=2^kk!(\prod_{i=1}^k (2i - 1)!)^2 \end{aligned} \]

有构造法:

  • \(4|n\) 时,可以删去 \(\{\frac{n}{2}\}\)

  • \(4|(n-2)\) 时,可以删去 \(\{2,\frac{n}{2}\}\)

  • \(2|(n-1)\) 时,可以删去 \(\{2,\frac{n-1}{2}, n\}\)

上述情况包含了所有非零自然数,故答案大于等于 \(n-3\)

剩下的就是求具体方案,构造解并非最优解,所以去要另外想办法快速判断平方数。

于是可以 xor-hashing。很牛逼,给每个质因数随机赋值,再质因数分解 xor 去求每个数的 hash 值,再求阶乘,一扫障碍,甚至可以用一些 STL 和其他容器做到 \(O(n)\),但是我太懒了。

2023.12.08

Codeforces - 1416D - Graph and Queries

(-)

很难崩,被卡常了,乐(大哭)。现在还没过这个题。

具体可以按时间做一遍最大生成树,当且仅当树边被删除时才会引发集合的分裂,然后倒着做一遍启发式合并,再按这种合并方式正着做一遍启发式分裂,用个 map 或者 set 就可以记录了。

时间复杂度 \(O(n\log_2^2n)\),只能说是联赛能过了。

Codeforces - 1903F - Babysitting

(-3)

Div2 最后一道题整这出?搞笑了。

只能说是线段树优化建图的 2-SAT 板题了。

二分答案,跑点数 \(O(n\log_2)\) 的 Tarjan,就完了,时间复杂度 \(O(n\log_2^2n)\),但是放最后一题根本来不及做吧。

Luogu - P4690 - [Ynoi2016]镜中的昆虫

(-17)

洛谷某管理员〇神玩多了,空间开成 64MB,卡了半个晚自习,66.8MB->63.67MB。关键有没有可能原题空间 512MB?卡分块你这样卡空间,评论区还有 \(O(n)\) 空间的分块,倒是一大堆 cdq 分治的被卡掉了。

这题是 CF848C 的困难版(做法类似)。会发现区间推平放在这里总的被修改的端点数仅仅是 \(O(n+m)\) 的。于是类似 ODT 地在 set 上维护区间以及颜色。不同于 ODT 在于其时间复杂度是确定的(因为只有区间推平操作)。

然后剩下的就和 CF848C 差不多了,cdq 分治计算贡献即可。

代码里有一个细节是

set < SQ > seq, sq[140005];
int cntdisc, disc[140005];

1.4e5 是为了卡空间设的,实际上应该设 2e5。

其他没啥了。只能说某出题人爱玩〇神。

2023.12.09

Atcoder - ARC059F - Unhappy hacking

(0)

神仙牛逼题,太牛逼了。

设一个长度为 \(m\) 的字符串 \(S\) 可以通过 \(n\) 步操作得到的方案数为 \(\mathrm{F}(S)\)。现在再同时考虑另一个等长的任意 01 字串 \(T\)

会发现最终决定 \(S\) 形态的操作只有恰好 \(|S|\) 个(“输入 0”或“输入 1”),这 \(|S|\) 个操作顺次连接可以得到 \(S\),当且仅当改变这 \(|S|\) 个的操作的加入字符才会改变 \(S\) 的最终形态。

所以实际上对于一种可以得到 \(S\) 的方案,将这 \(|S|\) 个操作构成的字串变为 \(T\) 只有唯一的方案,也就是说形成双射,即 \(\forall S,T, |S| = |T|,\{s, t|s \in S, t\in T\}\subseteq \{0,1\} : \mathrm{F}(S)=\mathrm{F}(T)\)

很牛逼,所以 \(\forall S : \mathrm{F}(S)=\frac{\mathrm{f}(|S|, n)}{2^{|S|}}\)。其中 \(\mathrm{f}(|S|, n)\) 表示 \(n\) 次操作可以得到长度为 \(|S|\) 的字串的方案数。

然后动态规划求解即可。

2023.12.13

[THUPC2023初赛]速战速决

(0)

很有意思的贪心,一眼看过去以为是和喵了个喵类似的题,其实只需要尽量让公共牌堆底部的自己有另一张的牌尽量多就可以了。

2023.12.21

[UR #11] 元旦老人与丛林 & [北京省选集训2019] 图的难题

(0)

这题太牛了,必须记录一下。

首先有一个性质,如果一个图 \(G(V,E)\) 满足可以被划分成两个边集使各自构成的子图相同,那么一个必要条件是 \(P:2|V|-2\ge E\)

会发现这个图的最坏情况是边集各自为生成树,否则一个边集内一定会出现环。显然其他情况的限制程度都小于这个。

但是可能会出现去掉一颗生成树后剩下一些单点和环。(所以这个只是必要条件)

而充要条件归纳则易知:如果一个图 \(G(V,E)\) 要满足题目给定的要求,那么它的子图和它都要满足 \(P\)

而将 \(P\) 转化可知:\(P:2|V|-2\ge E \Leftrightarrow E - 2|V| \le - 2\)。所以实际上我们需要求到最大的 \(E'-2|V'|\) 来判断。其实这个很类似最大密度子图的最小割部分,可以通过求闭合子图最大权来解决。考虑选一个点贡献为 \(-2\),选一条边贡献为 \(1\),选边必须选两个端点。但是略有不同在于这次倒是不用很在意正负问题,反而是因为这个时候其实网络流会选择一张空图回给你(也就是全部割与 \(s\) 连接的边,返回 \(m\)),也就是什么都不选。这样确实是可以让 \(E'-2|V'|\) 最大,但是实际上不应该出现这种情况。所以每次应该强制选一个点选择。具体来说就是断开它和 \(t\) 的连边并让最终的最大权再减去 \(2\)

实际上这样的时间是可以被卡掉的。时间复杂度上限为 \(O(Tn^3m)\)。但洛谷上数据范围很水,也就直接过了。

但是实际上应该在每次跑完最大流算法之后退流。这样可以保证复杂度过关。

于是就过了。时间复杂度不会算 qwq。

2023.12.22

[PA2021] Wystawa

(0)

牛逼啊喔趣。感觉最小值很难直接做,我们可以考虑判断是否存在方案满足最大子段和 \(\le x\)

然后会发现如果 \(a_i < b_i\) 那么这时选 \(i\) 一定不劣。假如有 \(K\) 个位置满足这样的条件。

那么首先钦定 \(K \ge k\),否则可以交换原本的 \(a,b\) 序列,同时 \(k \leftarrow n - k,K\leftarrow n-K\)

所以我们可以设想先选了 \(K\) 个位置,使得这时的最大子段和比所有方案都还要小。所以现在要解决的就是我们需要把 \(K-k\) 个位置从原本选择的 \(a_i\) 换成 \(b_i\),使得最大子段和最小。

策略应是,尽量少的损失下使被换成 \(b_i\)\(a_i\) 个数到达 \(K-k\) 个。

所以如果加上这个位置后维护的 \(c\) 的子段和 \(s\) 变成负数,可以发现其实应该尽量多地压榨这个出现的负数(因为在指针跳到下一个位置前为了保持最大会使 \(s \leftarrow 0\))。

当然,如果 \(s>x\) 那么直接返回 \(F\)

所以考虑尽量多地将前面的一些 \(a_i\) 变成 \(b_i\)。这样一定不会更劣。所以我们考虑维护一个数据结构保存 \(a_i\) 的贡献。贡献为 \(b_i-a_i\)。那么实际上我们就是将 \(b_i-a_i\) 最小的数通过这个负数给消掉。而每次我们让一个原本 \(c_i=a_i\) 的位置 \(c_i\leftarrow b_i\),会使得 \(s\leftarrow s+val\) 变大,同时我们成功地删去了 \(K-k\) 中的一个位置。如果 \(s\) 在下一个位置发生变化时变为正数则不能继续压榨了,结束这次压榨,同时原本下一个准备压榨 \(s\) 的贡献位置 \(i\) 的贡献应该增加 \(s\),因为这个位置下一次被变为 \(b_i\) 时贡献必须要经过这个 \(s\)。就会被减掉一些值。因为 \(s<0\) 所以不用担心下次拿出的贡献少考虑什么东西,因为如果要拿当前可以使用的贡献中的其他一部分就必须先使用这个位置 \(i\)。而加上这个 \(i\) 的贡献之后这段又会变成非负数。所以归纳一下,正确性是有的。

但是因为 \(c_i\leftarrow b_i\) 导致了最大子段和 \(>x\) 的情况上述的策略是没有考虑到的。所以我们可以考虑更进一步,考虑再记录一个 \(s_b\) 表示能选 \(b\) 时尽量选 \(b\) 的最大子段和。如果某个时刻 \(s_b > x\),那么考虑就要将前边的一些可以选 \(a_i\)\(b_i\) 的不定位置强制选择 \(a_i\)

仍然考虑尽量压榨,尽量少地选择强制为 \(a_i\) 的位置。所以我们应该选贡献尽量大的位置。考虑仍然在上述同一个数据结构中选择最大贡献的位置并使其强制选择 \(a_i\)(实际上相当于将 \(i\) 直接从数据结构中删去而不计入在删去的 \(K-k\) 个数中)。如果 \(s_b\le x\),那么停止选择。

当然最终不能忘记还没有选择的一些位置。这时仍然先选小的贡献,意义是删去 \(K-k\) 中的一个位置,同时让 \(s\) 加上贡献 \(val\)

最后的判断条件是 \(K-k\) 个位置全部完成替换且 \(s\le x\)。可以发现不会多替换了。如果存在某个子段的 \(s>x\),则应当已经提前退出了。

2023.12.25

Codeforces - 1917E - Construct Matrix

(-1)

首先考虑因为 \(n\) 为偶数,所以 \(k\) 为奇数时不可能满足条件。

其次,如果 \(4|k\),那么实际上在矩阵中一直放 \(2\times 2\) 的全为 \(1\) 的矩阵就可以了。

随后,如果 \(k \equiv 2 \mod 4\),那么可以证明如果 \(k \ne 2 \land k \ne n^2-2\) ,那么必然有解。

我们在右下角预留一个 \(4\times 4\) 的矩阵填,先填其他位置。

然后会发现这个 \(4\times 4\) 的矩阵中,除了 \(k' = 2\)\(k' = 14\) 的情况没法填,其他都有解。

又因为 \(k \ne 2 \land k \ne n^2-2\),所以对于 \(k'=2\) 在外面少填某个 \(2\times 2\) 的矩阵即可;对于 \(k'=14\) 在外面多填某个 \(2\times 2\) 的矩阵即可。

另外 \(k=2\)\(k=n^2-2\) 的情况,有解当且仅当 \(n=2\)

代码写得很丑因为是边想边写的。

Codeforces - 1917F - Construct Tree

(0)

不妨令 \(l_1 \le l_2 \le \cdots \le l_n\)

考虑必须要找出 \(l\) 的子集使得其和为 \(d\)。同时考虑如何构造出一棵可行的树。

把选出的部分 \(l'\) 展成一条链,可以发现如果最后满足答案,充要条件是存在一个点,使得所有未被选中的边都可以直接连在这个点上,且直径仍然为最初 \(l'\) 展出的链。

设这个点为 \(v'\),链的两端分别为 \(v_1,v_2\),发现满足条件当且仅当:

\[\max\{\mathrm{distance}(v',v_1),\mathrm{distance}(v',v_2)\} + l_e\le d \]

其中 \(e\) 为任意一条没有选中的边。

发现实际上可以直接动态规划。固定分界点,记录以上的两个值,考虑怎么转移。

有点说不清楚,对着代码讲吧。(出题人的实现很牛,照搬过来的)

bitset < D > f[D >> 1];
void Push (int x){
    for (int i = d >> 1;i >= 0;-- i){
        if (i + x <= (d >> 1))
            f[i + x] |= f[i];
        f[i] |= f[i] << x;
    } // 正常转移
}
void WORK (){
    f[0][0] = 1;
    int id = 1;
    for (int i = 1;i <= (d >> 1);++ i){ // 钦定前面一维的长度不会超过 d/2
        while (id <= n && ! (l[id] ^ i))
            Push (l[id]), id ++;
        res = 0;
        for (int j = id;j <= n;++ j)
            res += l[j];
        if (res <= d - i && f[i][d - i - res]){
            // 这里实际上在考虑前一维为 i 的情况,所以可以不需要先转移后面。
            // 小于等于 i 的边此时一定可以挂在分界点上,或者参与转移。
            // 大于 i 的边此时不能挂在分界点上,
            // 而固定前一维为 i ,所以大于 i 的边此时一定会挂在后一维的链上。
            // 通过 d 算另一维的大小,再减去还没有考虑转移的(就是大于 i 的)边的长度和,判断是否存在即可
            puts ("Yes");
            return ;
        }
    }
    puts ("No");
}

需要用 \(\textrm{bitset}\)

时间复杂度 \(O(\frac{nd^2}{w})\)\(w\)\(\textrm{bitset}\) 的位数。

posted @ 2023-12-25 20:36  Imcaigou  阅读(22)  评论(0编辑  收藏  举报