2019徐州网络赛G. Colorful String【回文树】

传送门

题意

定义一个字符串的值为字符串中不同字符的种数,求一个字符串的所有回文子串的值的和。

题解

算是回文自动机的板子题,可惜之前做的时候没学,直接构建回文树,dfs统计就行了。
写这个还是为了完善一下回文自动机的模板,之前写的那个模板不好用。

代码

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=3e5+10;
char s[N];
int n;
LL ans;
struct PAM{
	int tr[N][26],fail[N],len[N],cnt[N],tot,last,n;
	int getfail(int x){
		while(s[n]!=s[n-len[x]-1]) x=fail[x];
		return x;
	}
	void init(char *s){
		n=tot=last=0;
		cnt[0]=len[0]=cnt[1]=0;
		memset(tr[0],0,sizeof(tr[0]));
		memset(tr[1],0,sizeof(tr[1]));
		fail[0]=1;
		len[++tot]=-1;
		for(n=1;s[n]!='';n++){
			int c=s[n]-'a',cur=getfail(last);
			if(!tr[cur][c]){
				len[++tot]=len[cur]+2;cnt[tot]=0;
				memset(tr[tot],0,sizeof(tr[tot]));
				fail[tot]=tr[getfail(fail[cur])][c];
				tr[cur][c]=tot;
			}
			last=tr[cur][c];
			cnt[last]++;
		}
		for(int i=tot;i>=0;i--) cnt[fail[i]]+=cnt[i];
	}
	int count,vis[26];
	void dfs(int u){
		ans+=count*cnt[u];
		for(int i=0;i<26;i++){
			if(!tr[u][i]) continue;
			vis[i]++;if(vis[i]==1) count++;
			dfs(tr[u][i]);
			vis[i]--;if(!vis[i]) count--;
		}
	}
}pam;


int main(){
	scanf("%s",s+1);
	pam.init(s);
	pam.dfs(0);
	pam.dfs(1);
	cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12529732.html