LGP3449题解

其实每个串都不是回文串也能做的说。。。

题意:给定 \(n\) 个互不相同的串,两两拼接一共能够拼出 \(n^2\) 个串,问这 \(n^2\) 个串中有几个回文串。

首先假设拼接出来的串是 \(AB\),且 \(A\) 的长度大于 \(B\) 的长度。

\(AB\) 是回文串,那么回文中心一定在 \(A\) 上,那么就说明 \(B\) 的反串一定是 \(A\) 的前缀。将 \(A\) 去掉这个前缀后,剩下的后缀一定也是回文串。

然后问题就变成了了询问有多少个串是一个串的前缀,以及一个串的后缀是否是回文串。前者用 Trie,后者用 Hash 就好了。

每个串都是回文串只是方便了处理而已,处理后缀是否为回文串相当于处理前缀是否为回文串。

不懂为什么是紫题。。。

#include<algorithm>
#include<cstdio>
typedef unsigned ui;
const ui M=2e6+5,mod=998244353;
ui n,m,mx,tot(1),p[M],len[M],cnt[M],chi[M][26];char s[M],*S[M];bool Vis[M],*vis[M];long long ans;
inline void Insert(char*s,const ui&len){
	ui i,now(1);
	for(i=0;i^len;++i)!chi[now][s[i]-97]&&(chi[now][s[i]-97]=++tot),now=chi[now][s[i]-97];++cnt[now];
}
inline void Match(char*s,const ui&id,const ui&len){
	ui i,now(1);
	for(i=0;i^len;++i)cnt[now]&&vis[id][len-i-1]&&(ans+=cnt[now]),now=chi[now][s[i]-97];
}
signed main(){
	ui i,j,h1,h2;scanf("%u",&m);S[1]=s;vis[1]=Vis;p[0]=1;
	for(i=1;i<=m;++i)scanf("%u%s",len+i,S[i]),S[i+1]=S[i]+len[i],Insert(S[i],len[i]),len[i]>mx&&(mx=len[i]);
	for(i=1;i^mx;++i)p[i]=13331ull*p[i-1]%mod;
	for(j=1;j<=m;++j){
		vis[j+1]=vis[j]+len[j];h1=h2=0;
		for(i=0;i^len[j];++i)h1=(1ull*p[1]*h1+(S[j][i]-97))%mod,h2=(h2+1ull*p[i]*(S[j][i]-97))%mod,vis[j][i]=h1==h2;
	}
	for(i=1;i<=m;++i)Match(S[i],i,len[i]);printf("%lld",(ans<<1)+m);
}
posted @ 2022-01-11 14:46  Prean  阅读(31)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};