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 (1t104) — 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 (3n2105).

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 2105.

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[1i1]s[i+2,n]这两部分拼接,那么拼接后的字符串对应的哈希值就是(h[i1]h[0]p[i10+1])p[ni1]+(h[n]h[i+1]p[ni1])。然后把n1个拼接字符串的哈希值加到哈希表中,最后答案就是哈希表的大小。

  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[1i1]s[i+2,n],后一个字符串会保留s[1i]s[i+3,n],可以发现小于i的位置和超过i+2的位置都是一样的。因此如果前一个字符串的s[i+2]和后一个字符串的s[i]相同,那么这两个字符串就是相同的。

  因此对于1in2,比较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 @   onlyblues  阅读(166)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示