2023.5.29 NOI模拟赛总结

1.时间安排

7:10~8:20

T1:一眼网格图形式的平面图联通块数,用 \(V-E+F=平面图联通块数\) 就可以解决了。

T2:博弈背景的DP,感觉能倒序做DP,大概能口胡出一个单次询问 \(O(n^2)\) 的东西。

T3:数数题,只会暴力DP。

一开始T1想简单了,没有考虑到删除点后可能原来的周围的四个中的某些本来就是联通的,加上一个并查集就可以了,复杂度瓶颈在哈希表,\(n\) 只有1e5就写 std::unordered_map 了。

大样例实在是太水,自己写了个 \(n^4\) 的暴力对拍,正解比暴力好写(确信)。

拍了10分钟没问题,就不管了。

8:20~9:00

写了T2单次询问 \(O(n^2)\) 的DP,讨论先后手取min/max的细节非常多,调了很久,不过还是能过大样例的。

感觉 \(O(n^2)\) 的东西是预处理+单次询问 \(O(1)\),但是一开始一直认为只有正序DP才能做到这样的预处理,没想出来怎么做。

9:00~10:00

写了T3的暴力,拼起来有30分。

写了个FWT,结果常数巨大跑的比暴力还慢,就删掉了。

想写 \(k=2\) 的情况,感觉可以按位讨论容斥,但是没推出来正确的式子。

10:00~12:00

给T2的DP数组打了个表,发现只有三种取值:-1,0,1,但是 bitset 优化是单次询问 \(O(\frac{n^2}{w})\) 的,感觉没啥用。

试正序DP试了很久没调出来,最后突然意识到只需要把上面的倒序DP的第二维翻转一下从小往大做就可以了。

写完+调出来已经接近结束,没时间上bitset优化了。

result:

T1:100 T2:40 T3:20(数组开小了)

2.总结

T2:

改成 bitset 优化的形式后,问题变成了这样:

维护一个变量 \(p\) 表示当前是先手还是后手,每次遇到 \(a_i=0\),操作 \(f_{i,x}\leftarrow f_{i+1, x-1}\)\(f_{i,0}\leftarrow p\)\(p\leftarrow p \bigoplus 1\),否则如果 \(p=0\) 操作 \(f_{i,x}\leftarrow f_{i+1, x}\and f_{i+1, x-1}\),如果 \(p=1\) 操作 \(f_{i,x}\leftarrow f_{i+1, x}\or f_{i+1, x-1}\)

考虑快速维护这样的操作,考虑维护极长的连续1段,第一种操作相当于在开头加入一个长度为1的段,第二种操作相当于把所有段的左/右端点+1。

为了保证正确性复杂度,我们需要每次操作完删除空区间,然后合并相邻的区间,这样可以保住复杂度是均摊的 \(O(nlogn)\)

用 std::set 维护,具体的,一个 set 维护最短的区间,另一个 set 维护最短的区间间隙,可能还需要一些辅助的 set ,然后就是巨型分类讨论了。

T3:

部分分:CF1119H Triple

究极人类智慧题,除了暴力就是正解。

题意可以抽象为有若干个形式幂级数,求他们的异或卷积,用FWT可以做到 \(O(nm2^m)\)

考虑FWT的本质,对于一个 \(n\) 项的形式幂级数 \(f\)\(FWT(f)[i]=\sum_{j=0}^{n-1}(-1)^{c(i\and j)}f_j\),其中 \(c(i)\) 表示二进制下 \(i\) 的1的数量。

考虑 \(f\) 中只有 \(k\) 项有值,我们不放把第 \(t\) 项形式幂级数的FWT的形式改写一下:\(FWT(f_t)[i]=\sum_{j=1}^{k}(-1)^{c(p_{t,j}\and i)}a_j\)

现在复杂度变成了 \(O((n+m)2^m)\),但仍然过不去,不过给我们提供了很多可以拓展的空间。

我们考虑最终答案形式幂级数 \(ans\),考虑他的FWT \(s\),有 \(s[i]=\prod_{t=1}^{n}\sum_{j=1}^{k}(-1)^{c(p_{t,j}\and i)}a_j\)

因为是累乘,所以我们可以考虑对每种 \(a_j\) 前系数的取值算出来对应的出现次数,用快速幂就可以快速求解了,注意到一共有 \(2^k\) 种取值(仅考虑正负号)。

在继续研究前,我们可以进一步减少取值的种类,考虑对于 \(p_{t,j}\) 都异或上 \(p_{t,1}\),这样 \(a_0\) 前的系数永远是 \(1\),输出答案时只需要把答案形式幂级数做一个关于 \(\bigoplus_{t=1}^{n} p_{t,1}\) 的映射就好。

现在只需要考虑 \(2^{k-1}\) 种取值了,设第 \(i\) 种取值的出现次数是 \(cnt_i\)

我们希望能找出来 \(2^{k-1}\) 个方程,这样就可以求解出所有 \(cnt_i\) 了。

有一个天然的方程式 \(\sum_{i=1}^{2^{k-1}}cnt_i=n\),但远远不够。

下面的就是人类智慧了,考虑对 \(2^{k-1}-1\) 种集合做FWT,具体的,我们枚举钦定系数为-1的集合 \(S\),对于 \(1\leq t\leq n\),我们让当前的形式幂级数 \(g_S\) 中的第 \(\bigoplus_{i=2}^{k}[i\in S]p_{t,i}\) 加一。

求出来所有集合的形式幂级数的FWT。

根据FWT的定义,不难发现集合中的每一项可以看做累乘的一种取值,前面的系数是这个取值的在集合内的系数的异或。

进一步,我们发现只需要对 \(h[i]=FWT(g_S)[i]\) 这个形式幂级数做一下FWT,就得到了按状压顺序枚举的每种取值的出现次数,非常人类智慧。

于是就做完了,后面这部分为什么这么巧不会证,问就是观察+打表+手玩+人类智慧。

复杂度是 \(O((n+2^m)2^{k-1})\)

posted @ 2023-05-29 19:35  Displace  阅读(24)  评论(0)    收藏  举报