12.22 - 12.28 周总结

这一周练习了关于字符串专题。

复习了可持久化 trie,并学习了 AC 自动机。

AC 自动机

可以记录多个串互相的前缀关系,并用一个文本串可以匹配多个模式串。

简单来说就是在 trie 树上找 fail,具体方法是通过不断跳其父亲的 fail 来判断有没有这个相同的儿子,找到了则 fail 指向那个相等的节点,否则指向根(没有匹配)。

然而在实际匹配时,可能需要从一个节点转移到它原本不存在的子节点。此时若每次都暴力跳 fail 效率较低,因此可以预处理好每个节点对于所有字符的转移,即构建 Trie 图:每个点都能走向任意字符,保证 走到位置的串 和 当前串 + 字符 有最长的公共后缀,预处理整个过程的复杂度都是线性的,即为 \(\mathcal O(m)\),其中 \(m\) 为模式串总长。

代码
void add(string s) {
	int len = s.size(), u = 0;
	for(int i = 0; i < len; i++) {
		if(!son[u][s[i] - 'A']) son[u][s[i] - 'A'] = ++idx;
		u = son[u][s[i] - 'A'];
	}
	vis[u]++; // 模式串的结尾
}
void build_nfa() {
	queue<int> q;
	for(int i = 0; i < 26; i++) {
		if(son[0][i]) {
			fail[son[0][i]] = 0;
			q.push(son[0][i]);
		}
	}
	while(q.size()) {
		int u = q.front();
		q.pop();
		for(int i = 0; i < 26; i++) {
			if(son[u][i]) {
				fail[son[u][i]] = son[fail[u]][i]; // 儿子的 fail 就是自己 fail 的儿子
				vis[son[u][i]] += vis[fail[son[u][i]]]; // 继承 fail 链上的模式串结尾数量,使得匹配时走到该节点即可累加所有以该节点为后缀的模式串
				q.push(son[u][i]);
			} else {
				son[u][i] = son[fail[u]][i]; // 不存在这样的儿子就到 fail 去找
			}
		}
	}
}

可以用 AC 自动机解决一些有子串限制的计数(在 trie 图上 DP)。

电脑游戏

题目题目

这种 AC 自动机 DP 的题目一般状态都定义为 \(dp_{u,i}\)\(u\) 表示走到了 \(u\) 号节点,\(i\) 表示考虑到文本串的第 \(i\) 位。

对于这道题,\(dp_{u,i}\) 就表示走到 \(u\) 且考虑了 \(i\) 位的最大得分。

\[dp_{v,i+1}=\max_{u\to v} (dp_{u,i}+val_v) \]

其中 \(val_v\) 表示 \(v\) 及其 fail 链中的点作为模式串末尾的总次数,也就是走这一步的得分。

DP 部分
dp[0][0] = 0;
for(int i = 0; i < k; i++) {
	for(int u = 0; u <= idx; u++) {
		if(dp[i][u] == -0x3f3f3f3f) continue;
		for(int j = 0; j < 3; j++) {
			int v = son[u][j];
			dp[i + 1][v] = max(dp[i + 1][v], dp[i][u] + vis[v]);
		}
	}
}

这周的周练没有挂分,不过除了 T1 并没有过题。

T2 和 T3 都是有性质的,都没发现。

T2T2:“变换 \(x \gets (x+P) \bmod Q\) 会形成若干个环(周期),所有环互不相交且恰好覆盖 \([0,Q-1]\) 中的每个数。

T3T3:考虑逆序对数变化时可以关注一个数前面比它大的数的个数的变化。

T4:最大(二进制)与生成树。可以在 01-trie 上做类似异或生成树的方法,但将 0 子树 替换为 0 子树与 1 子树合并后的结果(对应按位与的性质),然后正常做即可。

不过有更巧妙的解法,按照 kruskal 的方法从大到小枚举边权,考虑哪些点之间会有这样的边权,发现如果将 \(x\mid 2^j\) 看做 \(x\) 的父亲,则凡是有父亲的点想连的边由它的父亲来连是不会更劣的,所以套用这个思路,连向它的父亲并计算权值和即可。

posted @ 2025-12-29 21:29  DHT666  阅读(1)  评论(0)    收藏  举报