杂题记录
想记啥记啥
CSP-S2024染色(dp)
考场上想的是被分割出来的两个区间内部的点还有贡献怎么办,现在重新看这个题,发现当时的dp是能考虑到这种情况的,因为这种情况在前面的dp已经算过了
NOIP2017 提高组宝藏(状压dp)
把挖宝藏的过程看成扩展一颗树,预处理一下每个状态之间转移的代价然后状压乱搞
[COTS 2018] 题日 Zapatak(哈希)
唐诗哈希题,通过各种哈希的奇淫巧技来判序列重排后是否一样
CF1503C(贪心)
神秘贪心,先把肯定有的代价算上然后再神秘贪心算额外的
CF802L(期望dp)
做dp,感觉是板题但是不会遂看题解,发现是先把dp式子写出来然后转化成一次函数的形式,感觉很聪明
[TJOI2011] 树的序(笛卡尔树)
先按照题意发现这个序列放到BST上后值和时间戳满足treap的性质,但是建树显然会T,然后交换一下两个值就转化成笛卡尔树了,启发了treap和笛卡尔树的关系,感觉很有脑子
「OICon-02」maxiMINImax(笛卡尔树)
首先它有三个区间,肯定不能枚举每一个,因为两个值都与中间那个区间的最小值有关系所以枚举中间那个区间,枚举区间是不必要的,只需要枚举最小值就行了,所以还要事先求一下每个值作最小值和最大值有多少个区间,然后还能知道有交集的两个区间贡献显然会是0,所以不用管相交的区间,只需要满足 \(max\{两边的区间\}\leq min _{中间那个区间}\) 这个的话直接把值从小到大枚举来算贡献就能保证现在枚举的中间的区间的最小值比另外两个区间的最大值大了,设这个值做最小值的区间个数为 \(c_i\) ,最大值的区间为 \(d_i\) 然后把原本式子拆开就变成了
\(c_i\times(w_i\times w_i \times \sum^{i-1}_{j=1}d_j\times \sum^{n}_{j=i+1}d_j-w_i\times(\sum^{i-1}_{j=1}d_j\times\sum^{n}_{j=i+1}(d_j\times w_j)+\sum^{i-2}_{j=1}d_j\times\sum^{n}_{j=i+1}(d_j\times w_j))+\sum^{i-1}_{j=1}(d_j\times w_j)\times\sum^{n}_{j=i+1}(d_j\times w_j)\)
看上去很复杂,其实只用两个树状数组维护 \(d_i\times w_i\) 和 \(d_i\) 就行了
[COTS 2018] 直方图 Histogram(笛卡尔树)
呃呃呃一眼看出来怎么做但是因为不会数论所以只能看题解,看到是直方图所以很套路的用笛卡尔树拆成一个个矩阵,然后很脑弹的是我不会求 \(\sum_{i=0}^r\sum_{j=0}^R max(h-\lceil \dfrac{p}{i+j+1}\rceil+1,0)\) 看题解发现是神秘数论然后直接抄过来了
CF1748E(笛卡尔树)
随便猜,转化成b数组和a数组构造出来的笛卡尔树一样,然后思考一下发现是对的,然后树形dp乱搞就好了
SP10628 COT - Count on a tree (主席树)
跟树上前缀和差不多,好像是1e5年前就看到这道题但是没有写?
CF888G(MST+trie)
因为有异或,还要求最小,所以先搞颗trie,然后观察发现最多有 \(n-1\) 个点有 \(2\) 个儿子,所以就把每个有 \(2\) 个儿子的节点的两个子树合并起来的最小代价加进答案(这里就是模拟菠萝),一开始把点权排个序,一个节点的子树对应的都是一段连续的区间,这样可以直接枚举区间内的数,更方便写(也可以启发式合并)
CF827F(最短路)
因为可能到了这个点还不能走,又不能停留,所以只能在一条边上反复横跳,所以在如果在 \(x\) 的时候到了 \(u\) 点,那么 \(x+2k\) 的时候也能到 \(u\) 点,所以就把每个点拆成奇点和偶点,表示在奇数时间和在偶数时间到达的这个点,维护点不好弄,因为在最小时间到达这个点可能会走不出去,所以维护边,因为你还可以在奇偶性相同的时间到达这条边,然后就采用类dij的东西来做
[省选联考 2022] 填树(拉格朗日插值法)
鏖战一下午,最后还是没能完全理解,首先能得出来一个树形dp,大概就是在一个节点把他的儿子们的信息合并起来,设 \(dp1_i\) 为 \(i\) 这个节点的子树里的方案数, \(dp2_i\) 为这些方案的权值和, \(dp3_i\) 为这个节点到子树内的一条链的方案数,\(dp4_i\) 为这些链的权值和,朴素的做法就是枚举这个链的最小值 \(L\) ,得出每个点的取值区间,即为 \([l_i,r_i]\) 和 \([L,L+k]\) 的交(设为$ [ll,rr]$),这里因为不一定会取到 \(L\) 这个最小值,所以容斥一下,再减去最小值为 \(L+1\) 的情况,然后时间复杂度为 \(O(nw)\) 瓶颈在于这个值域。
然后思考一下,发现问题就是跟 \([L,L+k]\) 这个滑动窗口有关,大部分情况 \([ll,rr]\) 在平滑地移动,而在 \(O(n)\) 个关键点处会有一些转折和改变(当\(L=l_i\) 或 \(L+k=l_i\) 或 \(L=r_i\) 或 \(L+k=r_i\)),也就是说答案是一个跟 \(L\) 相关的多项式
考虑简化一下这个问题,即在链上求方案数就是 \(\prod(rr-ll+1)\),这里的 \(rr-ll+1\) 就是关于 \(L\) 的一次函数,所以问题一最多是 \(n\) 次多项式,同理,问题二最多是 \(n+1\) 次多项式,然后就可以拉格朗日插值来做了
残缺的字符串(多项式乘法)
上课的时候没有认真听,下来看了下题解,然后理解了,首先考虑没有通配符的情况,可以想到用 \(\sum(a_i-b_j)\) 来算,判定就是是否为 \(0\) ,但是可能出现正负抵消,所以加个平方,即为 \(\sum(a_i-b_j)^2\) ,然后再考虑有通配符的情况,两个字符匹配的条件就是 \(a_i-b_j=0\) , \(a_i\) 为通配符,\(b_j\) 为通配符任意其一满足即可,所以可以把通配符全都设为 \(0\) ,然后把式子变成
\(\sum(a_i-b_j)^2\times a_i\times b_j\)
这里的乘就起到了或的作用,求和起到了与的作用,然后把这个式子拆开:
\(\sum {a_i}^3b_i-2\times \sum {a_i}^2{b_i}^2+\sum {a_i}{b_i}^3\)
然后把 \(a\) 反转一下,后面补一下 \(0\) ,就变成了一个卷积的形式
提交记录:懒得写了,没交
[SDOI2015] 序列统计(多项式乘法)
先得出来一个朴素dp:设 \(dp_{i,j}\) 表示选了 \(i\) 个,乘积为 \(j\) 的方案数,\(g_x\) 表示集合 \(S\) 中是否有这个数转移就是 \(dp_{i,j}=\sum dp_{i-1,j*invx}\times g_x\)
发现这个东西和卷积长的很像,但是这里满足的条件是 \(j*invx*g_x=j\) 而卷积的形式是和相等,考虑如何把积转化成和,发现可以用 \(log\) 来帮助转化,这里借助原根来表示 \(log\) ,设 \(pos_i\) 表示 原根的 \(pos_i\) 次方等于 \(i\) ,然后将原来集合里的 \(x\) 换成 \(pos_x\) ,最后式子就变成了 \(dp_{i,j}=\sum dp_{i-1,j-x}\times g_x\) 这样就满足了卷积的形式,然后快速幂求即可,做的时候有一个细节,就是 NTT 后要把跑到后面去的加到前面来,具体就是 \(ans_{i}+=ans_{i+m-1}\)
CF300D(多项式乘法)
根据题面的要求,每次分割正方形一定是从中间切割成4个小正方形,所以先定义 \(dp_{i,j}\) 表示一个边长为 \(i\) 的正方形,分割 \(j\) 次的方案数,转移:
\(dp_{i*2+1,j}=dp_{i,a}\times dp_{i,b}\times dp_{i,c}\times dp_{i,d}\) ,其中 \(a,b,c,d\) 就是每个正方形的切割次数,这样要T,注意到他们的 \(a+b+c+d\) 是相等的,所以使用卷积,即为\(dp_{2\times i+1}=dp_i \times dp_i\times dp_i\times dp_i\) 使用ntt来算,但是因为 \(N\leq 10^9\),所以换一下定义方式,把边长为 \(i\) 换成深度为 \(i\) 即可
提交记录:自己写了wa on test 2,改的话要把数组改成vector,不想改了交了题解 ,这样真的好吗
CF1709F(多项式乘法)
转化一下题面,一颗深度为 \(n\) 的满 \(01trie\) ,每条边的容量在 \([0,k]\) ,求以根为源点,叶子为汇点,最大流为 \(f\) 的方案数,可以先考虑朴素dp,每一层只用dp一个点即可,设 \(dp_{i,j}\) 为深度为 \(i\) 的节点,父亲向它的最大流量为 \(j\) 的方案数,先给出转移式:
\(dp_{i,j}=\sum dp_{ls,x}*dp_{rs,y}*(x+y>j? 1:k-j+1)\)
解释一下,限制流量的有两种情况:1.流量限制 2.左右儿子的限制,第一种,就是左右儿子的流量加起来大于 \(j\) ,但是父亲到这个点的容量为 \(j\),第二种就是左右儿子的流量和正好为 \(j\) ,这时父亲到当前节点的容量就可以是 \([j,k]\) ,考虑优化,对于第二种情况,因为有个 \(x+y=j\) 所以可以卷积来求,第一种情况后缀和即可
[Ynoi2005] rmscne(线段树)
题意就是给q个区间
\([l,r]\) ,求每个区间的子区间 \([l',r']\) 满足包含 \([l,r]\) 的所有元素的最短长度
先把问题离线下来,每个子段其实就是一个后缀的前缀,所以使用扫描线,扫到 \(r\) 时线段树上的每个叶子节点的值表示 \([l,r]\) 的最短前缀满足包含 \([l,r]\) 的所有元素的长度,维护这些值的最小值,可以发现这个东西就是一个等差数列赋值,但是我们要得到查询的区间,还要得到 \([l,r]\) 的最短后缀满足包含 \([l,r]\) 的所有元素,这里倒着跑一遍刚刚的算法就可以了
提交记录(洛谷上被卡常了过不去,不如世界最快的oj becoder)