[CSP-S 2023] 消消乐

题目

有一个长度为 $n$ 且仅由小写字母构成的字符串。我们称一个字符串是可消除的,当且仅当可以对这个字符串进行若干次操作,使之成为一个空字符串。

其中每次操作可以从字符串中删除两个相邻的相同字符,操作后剩余字符串会拼接在一起。

求这个字符串的所有非空连续子串中,有多少个是可消除的。

$1 \le n \le 2 \times 10^6$ ,且询问的字符串仅由小写字母构成。

题解

$f_i$ 为以 $i$ 为结尾的最短的合法串的左端点,用栈 $\mathcal{O}(n)$ 扫一遍。发现扫不全,一些点如左端点本来也可以有它左端点,但这里忽略了。考虑 $l_i$ 表示以 $i$ 为右端点最长合法串的左端点;为了方便统计答案,再设一个 $\text{cnt}_i$ 表示这几个连续的最短合法串的数量。再类似失配指针那样设一个 $\pi_{i,j}$ 表示在以 $i$ 为结尾的这几个连续最短合法串中最后一次把 $j$ 作为右端点的位置。在栈之后再扫一遍就可以扫完。

这样就可以转移完全。

复杂度 $\mathcal{O}(26n)$

代码

const int N = 2e6 + 5;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	struct node {
		int pos;
		char val;
	} stk[N];
	int n, f[N], l[N], cnt[N];
	int pos[N][30];
	char s[N];
	int top;
	ll ans;

	int main () {
		n = Read();
		scanf ("%s", s + 1);
		for (int i = 1; i <= n; i++) {
			if (stk[top].val == s[i]) l[i] = f[i] = stk[top].pos, top--, cnt[i] = 1, pos[i][s[i] - 'a'] = i;
			else stk[++top] = (node) {i, s[i]};
		}
		for (int i = 2; i <= n; i++) {
			if (f[i]) {
				if (l[f[i] - 1]) {
					l[i] = l[f[i] - 1], cnt[i] = cnt[f[i] - 1] + 1;
					for (int j = 0; j < 26; j++) 
						pos[i][j] = max(pos[i][j], pos[f[i] - 1][j]);
				}
			} else {
				if (pos[i - 1][s[i] - 'a']) {
					l[i] = f[i] = pos[i - 1][s[i] - 'a'];
					cnt[i] = 1;
					pos[i][s[i] - 'a'] = i;
					if (l[f[i] - 1]) {
						l[i] = l[f[i] - 1], cnt[i] = cnt[f[i] - 1] + 1;
						for (int j = 0; j < 26; j++) 
							pos[i][j] = max(pos[i][j], pos[f[i] - 1][j]);
					}
				} 
			}
			// printf ("%d %d %d\n", f[i], l[i], cnt[i]);
		}

		for (int i = n; i; i--) {
			ans += 1ll * cnt[i];
		}
		printf ("%lld\n", ans);
		return 0;
	}
}

int main () {
	freopen ("game.in", "r", stdin);
	freopen ("game.out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-10-23 07:28:26