洛谷P1117 优秀的拆分【Hash】【字符串】【好难不会】

题目描述

如果一个字符串可以被拆分为AABBAABB的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的。

例如,对于字符串aabaabaaaabaabaa,如果令 A=aabA=aab,B=aB=a,我们就找到了这个字符串拆分成 AABBAABB的一种方式。

一个字符串可能没有优秀的拆分,也可能存在不止一种优秀的拆分。比如我们令 A=aA=a,B=baaB=baa,也可以用 AABBAABB表示出上述字符串;但是,字符串 abaabaaabaabaa 就没有优秀的拆分。

现在给出一个长度为 nn的字符串SS,我们需要求出,在它所有子串的所有拆分方式中,优秀拆分的总个数。这里的子串是指字符串中连续的一段。

以下事项需要注意:

  1. 出现在不同位置的相同子串,我们认为是不同的子串,它们的优秀拆分均会被记入答案。

  2. 在一个拆分中,允许出现A=BA=B。例如 cccccccc 存在拆分A=B=cA=B=c。

  3. 字符串本身也是它的一个子串。

输入输出格式

输入格式:

每个输入文件包含多组数据。

输入的第一行只有一个整数TT,表示数据的组数。保证 1≤T≤101T10。

接下来 TT行,每行包含一个仅由英文小写字母构成的字符串SS,意义如题所述。

输出格式:

输出 TT行,每行包含一个整数,表示字符串SS 所有子串的所有拆分中,总共有多少个是优秀的拆分。

输入输出样例

输入样例#1:  复制
4
aabbbb
cccccc
aabaabaabaa
bbaabaababaaba
输出样例#1:  复制
3
5
4
7

说明

我们用S_{i,j}Si,j表示字符串 SS第 ii个字符到第jj个字符的子串(从11开始计数)。

第一组数据中,共有 33个子串存在优秀的拆分:

S_{1,4}=aabbS1,4=aabb,优秀的拆分为A=aA=a,B=bB=b;

S_{3,6}=bbbbS3,6=bbbb,优秀的拆分为 A=bA=b,B=bB=b;

S_{1,6}=aabbbbS1,6=aabbbb,优秀的拆分为 A=aA=a,B=bbB=bb。

而剩下的子串不存在优秀的拆分,所以第一组数据的答案是 33。

第二组数据中,有两类,总共44个子串存在优秀的拆分:

对于子串 S_{1,4}=S_{2,5}=S_{3,6}=ccccS1,4=S2,5=S3,6=cccc,它们优秀的拆分相同,均为A=cA=c,B=cB=c,但由于这些子串位置不同,因此要计算33 次;

对于子串 S_{1,6}=ccccccS1,6=cccccc,它优秀的拆分有 22种:A=cA=c,B=ccB=cc和 A=ccA=cc,B=cB=c,它们是相同子串的不同拆分,也都要计入答案。

所以第二组数据的答案是3+2=53+2=5。

第三组数据中,S_{1,8}S1,8和 S_{4,11}S4,11 各有 22 种优秀的拆分,其中S_{1,8}S1,8 是问题描述中的例子,所以答案是2+2=42+2=4。

第四组数据中,S_{1,4},S_{6,11},S_{7,12},S_{2,11},S_{1,8}S1,4,S6,11,S7,12,S2,11,S1,8 各有 11种优秀的拆分,S_{3,14}S3,14 有22 种优秀的拆分,所以答案是 5+2=75+2=7。

对于全部的测试点,保证1≤T≤101T10。以下对数据的限制均是对于单组输入数据而言的,也就是说同一个测试点下的TT组数据均满足限制条件。

我们假定nn为字符串SS的长度,每个测试点的详细数据范围见下表:

暴力Hash 80分TLE

枚举子串,枚举A的长度,hash比较

 1 #include <iostream>
 2 #include <set>
 3 #include <cmath>
 4 #include <stdio.h>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <map>
10 using namespace std;
11 typedef long long LL;
12 #define inf 0x7f7f7f7f
13 
14 const int maxn = 3e4 + 5;
15 
16 int t;
17 char s[maxn];
18 unsigned long long h[maxn], p[maxn];
19 int get_hash(int i, int j)
20 {
21     return h[j] - h[i - 1] * p[j - i + 1];
22 }
23 
24 
25 int main()
26 {
27     scanf("%d", &t);
28     p[0] = 1;
29     for(int i = 1; i < maxn; i++){
30         p[i] = p[i - 1] * 131;
31     }
32     while(t--){
33         scanf("%s", s + 1);
34         int len = strlen(s + 1);
35         for(int i = 1; i <= len; i++){
36             h[i] = h[i - 1] * 131 + s[i] - 'a' + 1;
37         }
38 
39         int ans = 0;
40         for(int i = 1; i <= len; i++){
41             for(int j = i + 1; j <= len; j += 2){
42                 int l = j - i + 1;
43                 for(int x = 1; x <= l / 2 - 1; x++){
44                     int y = l / 2 - x;
45                     if(get_hash(i, i + x - 1) == get_hash(i + x, i + 2 * x - 1)
46                        && get_hash(i + 2 * x, i + 2 * x + y - 1) == get_hash(i + 2 *  x + y, i + l - 1)){
47                         ans++;
48                     }
49                 }
50             }
51         }
52         printf("%d\n", ans);
53     }
54 
55     return 0;
56 }
View Code

稍微优化了一下的暴力Hash 95分TLE

用l[i]表示以i为结尾的满足AA串的个数, r[i]表示以i+1为开头的满足BB串的个数

 1 #include <iostream>
 2 #include <set>
 3 #include <cmath>
 4 #include <stdio.h>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <queue>
 9 #include <map>
10 using namespace std;
11 typedef long long LL;
12 #define inf 0x7f7f7f7f
13 
14 const int maxn = 3e4 + 5;
15 
16 int t;
17 char s[maxn];
18 unsigned long long h[maxn], p[maxn];
19 int l[maxn], r[maxn];
20 int get_hash(int i, int j)
21 {
22     return h[j] - h[i - 1] * p[j - i + 1];
23 }
24 
25 
26 int main()
27 {
28     scanf("%d", &t);
29     p[0] = 1;
30     for(int i = 1; i < maxn; i++){
31         p[i] = p[i - 1] * 131;
32     }
33     while(t--){
34         scanf("%s", s + 1);
35         int len = strlen(s + 1);
36         for(int i = 1; i <= len; i++){
37             h[i] = h[i - 1] * 131 + s[i] - 'a' + 1;
38         }
39 
40         int ans = 0;
41         for(int i = 1; i <= len; i++){
42             l[i] = r[i] = 0;
43             for(int j = i / 2; j >= 1; j--){
44                 if(get_hash(i - 2 * j + 1, i - j) == get_hash(i - j + 1, i)){
45                     l[i]++;
46                 }
47             }
48             for(int j = (len - i) / 2; j >= 1; j--){
49                 if(get_hash(i + 1, i + j) == get_hash(i + j + 1, i + 2 * j)){
50                     r[i]++;
51                 }
52             }
53         }
54         for(int i = 1; i <= len; i++){
55             ans += l[i] * r[i];
56         }
57         printf("%d\n", ans);
58     }
59 
60     return 0;
61 }
View Code

应该是一道后缀数组的题,后缀数组好难,不会。哈希也能处理,先研究一下。

猜你喜欢

转载自www.cnblogs.com/wyboooo/p/9860690.html