题解 AT4163 【[ARC099D] Eating Symbols Hard】

皎月半洒花

2020-03-05 21:39:16

Solution

(如果题解页面公式锅了可以选择去blog内看 这题数据奇水,水到我觉得这 $83$ 组数据就是在闹着玩的。谷这题唯一有代码的那篇题解,只要把第二组样例 `reverse` 一下就可以 `hack` 掉;我双哈希把俩模数写混了都能对 $71/83$。 _____ > 给定一个下标范围在 $[-\infty,\infty]$ 的数组。一开始指针在 $0$ 处。给定一段操作序列。求有多少个子序列的操作结果等价于整个序列的操作结果。操作有四种,左移/右移/某个位置$+1$/某个位置$-1$ 。 > > $1\leq n\leq 250,000$ 一拿到题首先考虑 $dp$ ,发现 $dp$ 不是很可做… 于是就发现,类似这种题目可以使用哈希。四种操作分别对应 $\times base^{-1}$、$\times base$、$+base$、$-base$ 。 考虑这样做如何去求某一段的哈希值。普通的求法原理如下: 对于每个 $p$ ,截止到 $p$ 的哈希值,如果将 $x$ 看做 $base$ 的一个等价,那么就是是 $$ \sum_{i=1}^ps_ix^{p-i} $$ 考虑将上式记作 $o(p)$ 。则片段 $[l,r]$ 的哈希值可以如此得到: ![](https://cdn.luogu.com.cn/upload/image_hosting/2qkkg86r.png) 考虑如果整个串的哈希值为 $q$,那么需要统计的是 $o(r)-o(l-1)\cdot x^{r-l+1}=q$ 。考虑从前至后用 $map$ 完成这个过程。由于不知道右端点的信息,需要对原式进行变形,即: $$\frac{q-o(r)}{x^r}=\frac{o(l-1)}{x^{l-1}}$$ 这样就可以做到 $l,r$ 无关了。随便选前缀或者后缀统计就好了。 但是注意到本题有个额外限制,最后只需要结果相同而不需要指针位置相同。所以需要在一开始哈希时稍微处理一下即可(这也是那篇挂了的题解的挂点)。 ```cpp #define mkp make_pair #define pll pair<LL, LL> const LL B1 = 237ll ; const LL B2 = 637ll ; const int N = 300010 ; const LL P1 = 998244353 ; const LL P2 = 1004535809 ; int n ; LL ans ; char s[N] ; LL I1, I2 ; LL g[N][2] ; LL S[N], T[N] ; map <pll, LL> buc ; LL expow(LL a, LL b, LL p){ LL ret = 1 ; while (b){ if (b & 1) (ret *= a) %= p ; (a *= a) %= p ; b >>= 1 ; } return ret ; } int main(){ cin >> n >> (s + 1) ; g[0][0] = g[0][1] = 1ll ; I1 = expow(B1, P1 - 2, P1) ; I2 = expow(B2, P2 - 2, P2) ; for (int i = 1 ; i <= n ; ++ i){ if (s[i] == '-'){ g[i][0] = g[i - 1][0] ; g[i][1] = g[i - 1][1] ; S[i] = (S[i - 1] - g[i][0] + P1) % P1 ; T[i] = (T[i - 1] - g[i][1] + P2) % P2 ; } if (s[i] == '+'){ g[i][0] = g[i - 1][0] ; g[i][1] = g[i - 1][1] ; S[i] = (S[i - 1] + g[i][0]) % P1 ; T[i] = (T[i - 1] + g[i][1]) % P2 ; } if (s[i] == '<'){ g[i][0] = g[i - 1][0] * I1 % P1 ; g[i][1] = g[i - 1][1] * I2 % P2 ; S[i] = S[i - 1] ; T[i] = T[i - 1] ; } if (s[i] == '>'){ g[i][0] = g[i - 1][0] * B1 % P1 ; g[i][1] = g[i - 1][1] * B2 % P2 ; S[i] = S[i - 1] ; T[i] = T[i - 1] ; } ++ buc[mkp(S[i], T[i])] ; } ++ buc[mkp(0, 0)] ; LL x, y ; for (int i = 0 ; i < n ; ++ i){ buc[mkp(S[i] , T[i])] -- ; x = (S[i] + S[n] * g[i][0] % P1) % P1 ; y = (T[i] + T[n] * g[i][1] % P2) % P2 ; ans += buc[mkp(x, y)] ; } cout << ans << endl ; return 0 ; } ```