Just A String(KMP)
Just A String(KMP)
题意:给一个字符串,枚举所有前缀与后缀,计 前缀 的后缀与 后缀 的前缀的最长公共部分为B,前缀剩余部分为A,后缀剩余部分为C(A,B,C表示长度),求所有前后缀的A * B * B * C,输出其异或和。(字符串长2000)
翻车体会:要求前缀的后缀,与后缀的前缀。想到用KMP处理后缀,因为后缀要求的是前缀,可用KMP快速解决前缀问题,然后查前缀的后缀,利用后缀跑KMP前缀必然匹配不到,我的想法是将原串复制接在后面,这样就能匹配到了(其实只要将原串作为匹配串再跑一遍KMP就行了),枚举所有后缀计算出每个后缀的KMP,然后计算每一个前缀的答案,这边我连接的时候并没有细节的再中间加一个#,出现了最长公共部分大于两个原串的情况,然后直接与原串大小取min,前缀匹配后缀计算出来的最长公共部分是无单调性的,导致wa。所以这题直接与原串匹配就好了。
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
ll t,n,nex[5007];
string s,s2;
void kmp(string s){
ll len=s.length();
ll l=0,r=1;
nex[l]=-1;
while(r<len){
if(l==-1||s[l]==s[r]){
l++;
r++;
nex[r]=l;
}
else l=nex[l];
}
}
int main(){
scanf("%lld",&t);
while(t--){
cin>>s;
n=s.length();
s+=s;
ll ans=0;
for(ll j=1;j<=n;j++){
s2="";
for(ll i=n-j;i<n;i++){
s2+=s[i];
}
kmp(s2);
ll l=0,r=0;
while(r<n){
if(l==-1||s2[l]==s[r]){
l++;
r++;
ans^=(r-l)*l*l*(j-l);
while(l==s2.length())l=nex[l];
}
else l=nex[l];
}
}
printf("%lld\n",ans);
}
}