← 全部文章

ARC099F Eating Symbols Hard 题解

本文目录(3 节)
  1. 题意
  2. 题解
  3. 代码

ARC099F Eating Symbols Hard

题意

  • 有一个长度为 2×109+12 \times 10^9 + 1 的整数序列 a−109…109a_{-10^9 \dots 10^9},和一个整数 pp,一开始均为 00。
  • 对于一个仅包含 +->< 的字符串,按顺序依次执行每个字符对应的操作,可以得到新的 aa 序列。
  • 每个字符对应的操作如下:
    • +:apa_p 加上 11。
    • -:apa_p 减去 11。
    • >:pp 加上 11。
    • <:pp 减去 11。
  • 现在有一个长度为 nn 的仅包含 +->< 的字符串 ss,问有多少个 ss 的非空子串得到的 aa 序列与 ss 得到的 aa 序列一样。
  • n≤2.5×105n \le 2.5 \times 10^5。

题解

首先对于 aa 显然可以 hash,hash 函数设为模意义下的 ∑i=−109109aixi\sum_{i=-10^9}^{10^9} a_ix^i,其中 xx 是一个自己设定的 base,注意可能要多个 base/mod。

对于一个操作序列,我们可以得到其操作完后的 hash 值以及 pp 所在的位置 (h,p)(h,p),显然这个信息是可以合并的,merge⁡((hi,pi),(hj,pj))=(hi+hjxpi,pi+pj)\operatorname{merge}((h_i,p_i), (h_j,p_j)) = (h_i + h_jx^{p_i}, p_i + p_j)。

预处理出 ss 的每个前缀 s[:i]s[:i] 对应的 (hi,pi)(h_i,p_i),题目要求 ss 与 s[i:j]s[i:j] 得到的 hh 相等,等价于 s[:i−1]+ss[:i-1] + s 与 s[:j]s[:j] 得到的 hh 相等,即 hi−1+hnxpi−1=hjh_{i-1} + h_{n}x^{p_{i-1}} = h_j。

从左往右扫 jj,用个 map 记录 hi−1+hnxpi−1h_{i-1} + h_nx^{p_{i-1}} 的值的个数即可,时间复杂度 O(nlog⁡n)\mathcal O(n \log n)。

代码

const int N = 2.5e5 + 7, M = 2;
int n;
char s[N];
struct H {
	vector<modint> a;
	inline H() { a.resize(M); }
	inline modint &operator [] (int i) { return a[i]; }
	inline friend bool operator < (H x, H y) { return x.a < y.a; }
	inline friend H operator + (H x, H y) {
		for (int i = 0; i < M; i++) x[i] += y[i];
		return x;
	}
	inline friend H operator - (H x, H y) {
		for (int i = 0; i < M; i++) x[i] -= y[i];
		return x;
	}
	inline friend H operator * (H x, H y) {
		for (int i = 0; i < M; i++) x[i] *= y[i];
		return x;
	}
} a[N], x, y, h[N];
map<H, int> f;
ll ans;

int main() {
	srand(time(0));
	rd(n), rds(s, n);
	for (int i = 0; i < M; i++)
		a[0][i] = 1, x[i] = rdm(1, P - 1), y[i] = 1 / x[i];
	for (int i = 1; i <= n; i++)
		switch (s[i]) {
			case '+' : h[i] = h[i-1] + (a[i] = a[i-1]); break;
			case '-' : h[i] = h[i-1] - (a[i] = a[i-1]); break;
			case '>' : h[i] = h[i-1], a[i] = a[i-1] * x; break;
			case '<' : h[i] = h[i-1], a[i] = a[i-1] * y; break;
		}
	for (int i = 1; i <= n; i++) ++f[h[i-1]+h[n]*a[i-1]], ans += f[h[i]];
	print(ans);
	return 0;
}

标签:Hash、前缀和/差分、组合计数

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…