列表

详情


NC13821. Just A String

描述

何老师手中有一个字符串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|2|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)的异或和。

示例1

输入:

1
abcab

输出:

13

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 191ms, 内存消耗: 528K, 提交时间: 2020-09-29 15:44:28

#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);
	}
}

C++(clang++11) 解法, 执行用时: 168ms, 内存消耗: 384K, 提交时间: 2020-10-24 00:24:47

#include<bits/stdc++.h>
using namespace std;
int T,n,m,f[2009];
long long ans;
char s[2009];
void work(char *c){
	m=strlen(c+1);
	for(int i=1,j=0;i<=m;f[++i]=++j){
		while(c[i]!=c[j]&&j)j=f[j];
	}
	for(int i=1,j=1;i<=n;++i,++j){
		while(s[i]!=c[j]&&j)j=f[j];
		ans=ans^(1ll*j*j*(m-j)*(i-j));
		
	}
}
int main(){
	scanf("%d",&T);
	while(T--){
		ans=0;
		scanf("%s",s+1);
		n=strlen(s+1);
		for(int i=1;i<=n;++i){
			work(s+i-1);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

上一题