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 }

 

 

 

转载于:https://www.cnblogs.com/letlifestop/p/10906405.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值