THUWC前集训Day6

THUWC前集训Day6

T1 string

关键就是求串\(S\)的所有本质不同子串的本质不同子串数量和,记为1型串和2型串。

首先你最好做过区间本质不同子串数量,和那个是一样的套路。

就是先建SAM,然后依次加入右端点\(r\)并考虑所有以\(r\)为右端点的子串。对SAM的影响就是改变了一条到根的链上的所有点的endpos,钦定所有2型串在当前最晚的出现位置产生贡献。从下往上爬这条链,如果某个点之前已经被访问过,那么其表示的所有子串的贡献都撤销(在线段树上区间-1即可),并标记为被\(r\)访问。最后将\([1,r]\)区间+1.此时线段树上\([l,r]\)的区间和即为\([l,r]\)的本质不同子串数量,爬的过程可以用LCT维护,可以做到每个\(r\)复杂度均摊\(\mathcal O(\log n)\)

现在要对所有1型串求这个事情。我的做法是让每个1型串在最早的出现位置产生贡献,先假设都不同,答案加上\(\sum_{i=1}^rSum(i,r),Sum(i,r)\)为线段树上\([i,r]\)区间和 。爬的时候如果某个点之前已经被访问过,那么将其贡献(设其表示了\([minl,maxl]\)这些串,那么贡献为\(\sum_{i=minl}^{maxl}Sum(i,r)\) )撤销。令线段树维护区间加,询问区间后缀和的和即可。

复杂度\(\mathcal O(n\log n)\). (注意不是2个log,LCT的虚实边切换是均摊\(O(1)\)的)

My code

T2 Cubelia

关键就是询问一个区间的所有子区间的最小值之和。

离线可以莫队或者排序之后线段树,不必展开。

做法是求出最小值位置\(pos\),那么区间分三种:跨越\(pos\),在\([l,pos-1]\)中,在\([pos+1,r]\)中。

\([pos+1,r]\)为例。先用单调栈预处理\(g(i)=\sum_{j=1}^i\max_{k=j}^ia_k\)。那么\([1,i]\)的答案即为\(\sum_{j=1}^ig(j)\).

\([1,r]\)的答案减去\([1,pos]\)的答案即为右端点在\([pos+1,r]\)中的所有子区间最小值之和,我们再容斥掉左端点在\([1,pos]\)右端点在\([pos+1,r]\)的部分:因为\(pos\)\([l,r]\)的最小值,\(\forall pos<i\le r,s_i>s_{pos}\),所以容斥掉的部分就是\(g(pos)\times (r-pos)\).

RMQ可以ST表或分块ST表(或标准RMQ,若你愿意)。复杂度\(\mathcal O(n\log n+Q)\)\(\mathcal O(n+Q)\)

My code

T3 背包++

法一:

\(f(i,j,k)\)表示考虑前\(i\)个物品,体积为\(j\)能否由\(k\)种物品拼成。

\[f(i,j,k)=f(i-1,j,k)OR_{x=1}^cf(i-1,j-1,k-vx) \]

暴力转移+bitset压位可以做到\(O(n^4/\omega)\)

将所有\(mod\ v=p\)\(k\)一起考虑。实际上就变成询问若干段区间的bitset的or的结果(开始一些区间长度不足\(c\),之后全为\(c\))。每\(c\)位设一个关键点,处理前面\(k\)个bitset的or的结果和后面\(k\)个bitset的结果,查询就找一个最近的关键点查询。

复杂度\(\mathcal O(n^3/\omega)\).

My code

posted on 2020-12-23 18:05  万弘  阅读(98)  评论(0编辑  收藏  举报