摘要:
题面 基本上所有树剖题都可以用LCT维护。两种思路,一种是直接暴力地维护每个点表示的区间的左右端点颜色和颜色段数,另一种是把连接同种颜色的边边权设为 \(0\),不同种颜色设为 \(1\),然后维护路径和即可。 一个注意的点在于LCT中的 \(tag\) 是对所有跟左右有关的值进行取反的标记。一定不 阅读全文
摘要:
题面 对模式串建广义SAM,对于每个匹配串,首先求出 \(sl_i\) 表示以 \(i\) 为结尾的后缀的最长匹配长度。设 \(dp_i\) 表示 \(1\sim i\) 的最长匹配长度和,二分答案 \(mid\) 之后,有如下 dp 方程: \[ dp_i=\max(dp_{i-1},\max_{ 阅读全文
摘要:
题面 统计一个后缀和数组 \(suf_i\),其中 ) 为 \(1\),( 为 \(-1\),那么一个子串 \(s_{l,r}\) 是一个合法括号序列,当且仅当 \(\min_{l\leq k \leq r}suf_k\geq suf_{r+1}\),并且 \(suf_l=suf_{r+1}\)。 阅读全文
摘要:
题面 把所有叶子拎起来当根,合并成一棵trie之后建广义 SAM(我直接每个叶子直接跑的,每次 \(lastpos\) 重置,也可过)。 点击查看代码 const int N=1e5+13,M=2e6+13; int n,m,nxt[M<<1],len[M<<1],ptot=1; std::vect 阅读全文
摘要:
题面 对 \(n\) 个串建广义 SAM,每个点开一棵线段树维护 parent 树子树内的所有点都被哪些串走到过。这个直接线段树合并即可。注意分裂出来的点也需要update(我也不知道为何,反正不update会WA)。 点击查看代码 const int N=5e5+13,M=5e5+13,logN= 阅读全文
摘要:
题面 虽然 \(n,m\leq 5000\),但是这题是 \(O((n+m)|\Sigma|)\) 的。首先建 \(S\) 的 SAM,拿 \(T\) 上去跑可以得到 \(T\) 每个前缀的匹配区间(在 \(S\) 中只出现一次)。接着建 \(T\) 的 SAM,也可以求出每个前缀在 \(T\) 中 阅读全文
摘要:
题面 循环同构的话很容易想到把串延长一倍,跑的时候找所有长度为 \(n\) 的公共子串的出现次数即可。 点击查看代码 const int N=3e6+13; char s[N<<1]; int nxt[N<<1],len[N<<1],ptot=1,lastpos=1,cnt[N<<1]; std:: 阅读全文
摘要:
题面 对 \(T\) 建 SAM,拿 \(S\) 进去跑,可以得到每个 \(S\) 的前缀 \(S_i\) 的最长匹配后缀长度 \(sl_i\)。那么对于一个询问 \([l,r]\),答案就是 \(\max_{l\leq i\leq r}\{\min(sl_i,i-l+1)\}\)。 里面这个 \( 阅读全文
摘要:
题面 本质不同第 \(k\) 小。对 SAM 上每个点求一个 \(b_i\) 表示从这个点开始往后走能走到的本质不同的子串个数。然后拿 \(k\) 在自动机上跑即可。 点击查看代码 const int N=9e4+13; char s[N]; int nxt[N<<1],len[N<<1],ptot 阅读全文
摘要:
题面 拿出出现次数为 \(k\) 的点,给这个点表示的长度区间 \(+1\),这个可以使用差分解决。 点击查看代码 const int N=1e5+13; char s[N]; int nxt[N<<1],len[N<<1],ptot,lastpos,ind[N<<1]; ll cnt[N<<1], 阅读全文
摘要:
题面 给一个串建 SAM,另一个串在上面跑。 点击查看代码 const int N=2.5e5+13; char s[N],t[N]; int nxt[N<<1],len[N<<1],ptot=1,lastpos=1; std::unordered_map<int,int> son[N<<1],bo 阅读全文
摘要:
题面 每个点 \(u\) 代表 \(len_ u-len_{nxt_u}\) 这么多串。这个也可以 DAWG dp 求得,不过太麻烦了。 点击查看代码 const int N=1e5+13; int n,nxt[N<<1],len[N<<1],lastpos=1,ptot=1; char s[N]; 阅读全文
摘要:
题面 拆出来的点贡献为 \(0\),其他贡献为 \(1\),在 DAWG 上统计一个后缀和即可。 点击查看代码 const int N=1e6+13,M=26; int n,len[N<<1],nxt[N<<1],ptot=1,lastpos=1,ind[N<<1]; ll cnt[N<<1]; s 阅读全文
摘要:
题面 当年见这题的时候还是初三的年轻选手。现在已经是老选手了…… 考虑推式子: \[ \begin{aligned} &\ \ \ \ \ \sum_T (\sum_{i=1}^{n-1}w_{e_i})\times\gcd_{i=1}^{n-1}w_{e_i}\\ &=\sum_T \big(\s 阅读全文
摘要:
题面 板子。注意模数不是质数的 \(\det\): inline int det(int n){ int res=1;bool flag=0; for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j){ while(a[i][i]){ int tmp=a[j][i] 阅读全文
摘要:
题面 这题挺有意思的。平常的矩阵树定理求的是 \[ \sum_T\prod_{e\in T}w_e \] 这题要求 \[ \begin{aligned} \sum_T\prod_{e\in T}p_e\prod_{e\not\in T}(1-p_e) &=\sum_T(\prod_{e\in T}p 阅读全文
摘要:
题面 模板题。直接容斥+矩阵树。复杂度 \(O(2^{n-1}(n-1)^3)\) 可以通过。 阅读全文
摘要:
题面 一个显然的做法是树剖之后dfs序线段树套时间线段树,直接做的复杂度是 \(O(n\log^3 n)\)。其实也可以把询问离线下来,做一个线段树分治,用树套树维护。 这样做比较麻烦,所以考虑另外一种思路:二分答案。因为有很多询问,不妨放在一起二分,所以可以想到整体二分。使用类似树上差分的思想,对 阅读全文
摘要:
题面 比较经典的带修树上第 \(k\) 大问题。通常的做法是树剖树套树然后树上二分,一般3到4个 \(\log\)。这个题还可以用整体二分解决。 思考一下这道题目的整体二分过程:二分一个答案 \(mid\),把所有的 \(>mid\) 的修改放到一个数据结构里,然后查询树上路径和。这显然可以使用树剖 阅读全文
摘要:
题面 \(q\) 次查询矩形第 \(k\) 小。考虑使用整体二分,二分一个值 \(mid\),矩形中小于等于 \(mid\) 的数设为 \(1\),大于 \(mid\) 的数设为 \(0\),统计每个询问的矩形中的和,若大于等于 \(k\),表示答案应该在 \([L,mid]\) 范围内,放到左边继 阅读全文