Just A String(kmp)
链接:https://ac.nowcoder.com/acm/problem/13821
来源:牛客网
题目描述
何老师手中有一个字符串S,他发现这个字符串有一个神奇的性质,取出一个长为i的前缀(就是由S的前i个字符顺序构成的字符串)prei和一个长为j的后缀(就是由S的后j个字符顺序构成的字符串)sufj之后,总是存在三个字符串A,B,C(可能为空)使得prei=A+B,sufj=B+C, 虽然这听起来像是一句废话。
显然三元组A,B,C不总是唯一的,何老师从所有可能的三元组中找到B最长的,很容易知道这样的三元组是唯一的,并且认为prei和sufj的契合度就是f(i,j)=|A|*|B|*|B|*|C|,现在你需要帮何老师算出所有f(i,j)(0 ≤ i,j ≤ n)的异或和。
这里|X|表示字符串X的长度,X+Y表示将两个字符串X和Y顺序拼接起来后得到的新字符串。
输入描述:
第一行是一个正整数T(≤ 500),表示测试数据的组数, 每组测试数据,包含一个仅由小写字母构成的非空字符串S(|S| ≤ 2000), 保证满足|S|>200的数据不超过5组。
输出描述:
对于每组测试数据,输出所有f(i,j)(0 ≤ i,j ≤ n)的异或和。
具体思路:
首先,我们枚举每个后缀,判断当前总的字符串从第0个位置开始到这个字符串的i位置与当前枚举的后缀的重叠长度。
这个过程和kmp的nex数组是类似的。
nex[i]代表的是从0开始到第i个位置,前缀和后缀完全匹配的最大长度。
com[i]就代表从0到i这个字符串后缀与匹配串前缀的重叠长度。
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 # define ll long long
4 # define inf 0x3f3f3f3f
5 const int maxn = 2e5+100;
6 char str[maxn];
7 int nex[maxn];
8 int com[maxn];
9 void getnex(char *s)
10 {
11 nex[0]=nex[1]=0;
12 int len=strlen(s);
13 for(int i=1; i<len; i++)
14 {
15 ll j=nex[i];
16 while(j&&s[i]!=s[j])
17 j=nex[j];
18 nex[i+1]= (s[i]==s[j]?j+1:0);
19 }
20 }
21 void kmp(char *str1,char *str2)
22 {
23 getnex(str2);
24 int len1=strlen(str1);
25 int len2=strlen(str2);
26 ll j=0;
27 for(int i=0; i<len1; i++)
28 {
29 while(j&&str1[i]!=str2[j])
30 j=nex[j];
31 if(str1[i]==str2[j])
32 j++;
33 if(j==0)
34 com[i]=0;
35 else
36 com[i]=j;
37 if(j==len2)
38 j=nex[j];
39 }
40 }
41 int main()
42 {
43 int T;
44 scanf("%d",&T);
45 while(T--)
46 {
47 ll ans=0;
48 scanf("%s",str);
49 int len=strlen(str);
50 for(int i=1; i<=len; i++)
51 {
52 for(int j=0; j<=len; j++)
53 com[j]=0;
54 kmp(str,str+(len-i));
55 for(int j=0; j<len; j++)
56 {
57 ll A=j+1-com[j];
58 ll B= com[j];
59 ll C= i-com[j];
60 ll tmp=A*B*B*C;
61 ans^=tmp;
62 }
63 // cout<<i<<" "
64 }
65 printf("%lld\n",ans);
66 }
67 return 0;
68 }
我的kmp代码不知道哪里错了,样例过了,但是提交却一组也不对。希望路过的神仙看一下哪里的问题 !!!∑(゚Д゚ノ)ノ
1 #include<bits/stdc++.h>
2 using namespace std;
3 # define ll long long
4 # define inf 0x3f3f3f3f
5 const int maxn = 2e5+100;
6 char str[maxn];
7 int nex[maxn];
8 int com[maxn];
9 void getnex(char *s)
10 {
11 int len=strlen(s);
12 nex[0]=-1;
13 int i=0,j=-1;
14 while(i<len)
15 {
16 if(j==-1||s[i]==s[j])
17 {
18 i++;
19 j++;
20 nex[i]=j;
21 }
22 else
23 j=nex[j];
24 }
25 }
26 void kmp(char *str1,char *str2)
27 {
28 getnex(str2);
29 int len1=strlen(str1);
30 int len2=strlen(str2);
31 int i=0,j=0;
32 while(i<len1&&j<len2)
33 {
34 if(j==-1||str1[i]==str2[j])
35 {
36 i++;
37 j++;
38 }
39 else
40 j=nex[j];
41 com[i-1]= ( j==-1? 0 : j );
42 if(j==len2)
43 j=nex[j];
44 }
45 }
46 int main()
47 {
48 int T;
49 scanf("%d",&T);
50 while(T--)
51 {
52 ll ans=0;
53 scanf("%s",str);
54 int len=strlen(str);
55 for(int i=1; i<=len; i++)
56 {
57 for(int j=0; j<=len; j++)
58 com[j]=0;
59 kmp(str,str+(len-i));
60 for(int j=0; j<len; j++)
61 {
62 ll A=j+1-com[j];
63 ll B= com[j];
64 ll C= i-com[j];
65 ll tmp=A*B*B*C;
66 ans^=tmp;
67 }
68 // cout<<i<<" "
69 }
70 printf("%lld\n",ans);
71 }
72 return 0;
73 }