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
",ans);
	}
}

原文地址:https://www.cnblogs.com/whitelily/p/13750184.html