D. Remove Two Letters

D. Remove Two Letters

Dmitry has a string $s$, consisting of lowercase Latin letters.

Dmitry decided to remove two consecutive characters from the string $s$ and you are wondering how many different strings can be obtained after such an operation.

For example, Dmitry has a string "aaabcc". You can get the following different strings: "abcc"(by deleting the first two or second and third characters), "aacc"(by deleting the third and fourth characters),"aaac"(by deleting the fourth and the fifth character) and "aaab" (by deleting the last two).

Input

The first line of input data contains a single integer $t$ ($1 \le t \le 10^4$) — number of test cases.

The descriptions of the test cases follow.

The first line of the description of each test case contains an integer $n$ ($3 \le n \le 2 \cdot 10^5$).

The second line of the description of each test case contains a string $s$ of length $n$ consisting of lowercase Latin letters.

It is guaranteed that the sum of $n$ for all test cases does not exceed $2 \cdot 10^5$.

Output

For each test case print one integer — the number of distinct strings that can be obtained by removing two consecutive letters.

Example

input

7
6
aaabcc
10
aaaaaaaaaa
6
abcdef
7
abacaba
6
cccfff
4
abba
5
ababa

output

4
1
5
3
3
3
1

Note

The first example is explained in the statement.

In the third example, the following strings are obtained: "cdef", "adef", "abef", "abcf", "abcd".

In the seventh example, any deletion will result in the string "aba".

 

解题思路

  一开始想到字符串哈希,结果人品不好被hack了。取$P = 131$被下面的数据hack了,正确答案应该是$17$,而$P=131$得到的答案是$16$。

1
18
aaibfprdokxvipsqaa

  但有意思的是$P = 13331$就可以AC了,真就玄学。

  比如如果要把$s[i]$和$s[i+1]$删除,然后将$s[1 \sim i-1]$和$s[i+2, n]$这两部分拼接,那么拼接后的字符串对应的哈希值就是$(h[i-1] - h[0] \cdot p[i-1 - 0 + 1]) \cdot p[n - i - 1] + (h[n] - h[i+1] \cdot p[n - i - 1])$。然后把$n-1$个拼接字符串的哈希值加到哈希表中,最后答案就是哈希表的大小。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef unsigned long long ULL;
 5 
 6 const int N = 2e5 + 10, P = 13331;
 7 
 8 char s[N];
 9 ULL h[N], p[N];
10 
11 ULL get(int l, int r) {
12     if (l > r) return 0;
13     return h[r] - h[l - 1] * p[r - l + 1];
14 }
15 
16 void solve() {
17     int n;
18     scanf("%d %s", &n, s + 1);
19     p[0] = 1;
20     for (int i = 1; i <= n; i++) {
21         p[i] = p[i - 1] * P;
22         h[i] = h[i - 1] * P + s[i];
23     }
24     unordered_set<ULL> st;
25     for (int i = 1; i < n; i++) {
26         st.insert(get(1, i - 1) * p[n - i - 1] + get(i + 2, n));
27     }
28     printf("%d\n", st.size());
29 }
30 
31 int main() {
32     int t;
33     scanf("%d", &t);
34     while (t--) {
35         solve();
36     }
37     
38     return 0;
39 }

  给出正解。

  考虑删除$s[i]$和$s[i+1]$,和$s[i+1]$和$s[i+2]$后所得到的两个字符串,前一个字符串会保留$s[1 \sim i-1]$和$s[i+2, n]$,后一个字符串会保留$s[1 \sim i]$和$s[i+3, n]$,可以发现小于$i$的位置和超过$i+2$的位置都是一样的。因此如果前一个字符串的$s[i+2]$和后一个字符串的$s[i]$相同,那么这两个字符串就是相同的。

  因此对于$1 \leq i \leq n - 2$,比较$s[i]$和$s[i+2]$,如果相同则存在一个字符串是重复的。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e5 + 10;
 5 
 6 char s[N];
 7 
 8 void solve() {
 9     int n;
10     scanf("%d %s", &n, s + 1);
11     int ret = n - 1;
12     for (int i = 1; i < n; i++) {
13         if (s[i] == s[i + 2]) ret--;
14     }
15     printf("%d\n", ret);
16 }
17 
18 int main() {
19     int t;
20     scanf("%d", &t);
21     while (t--) {
22         solve();
23     }
24     
25     return 0;
26 }

 

参考资料

  Codeforces Round 855 (Div. 3) Editorial:https://codeforces.com/blog/entry/113477

posted @ 2023-03-04 14:36  onlyblues  阅读(145)  评论(0编辑  收藏  举报
Web Analytics