Colorful String(The Preliminary Contest for ICPC Asia Xuzhou 2019)-回文树

原题链接
Colorful String(The Preliminary Contest for ICPC Asia Xuzhou 2019)-回文树_第1张图片
比赛打到自闭,题目都不想看(被OI暴虐,自己太不争气了55555)。。。
这道题用回文树(回文自动机)板子套一下就没事了,网上也有人用“马拉车”做出来了(这东西很玄学),还有的人用主席树算权值(佛了,直接状压一下不就完事了吗,然后在回文树里面改一两句代码,转移一下状态)。
比赛的时候用“马拉车”在那里磨,一直搞不出来。比赛完,看到题解才知道有回文树这种东西,然后恶补了一下就把这道题做出来了。
这里只说一下回文树几个难以理解的地方(基础的东西可以。。。你懂的)
1.num[i]统计的是,包含在当前回文串之内,以s[i]结尾的回文串的个数,num[now]=num[fail[now]]+1这句代码应该容易理解吧,其实说白了,这个计数器没什么用,至少对于这道题来说是这样的
2.cnt[i]统计的是,当前回文串在主串中出现的次数(最后跑一遍fail才能完全统计出来,具体可以自己去了解一下)
3.回文树节点的个数减2就是回文串的种类数
4.num[i]之和就是所有回文串的个数(不去重,你懂的)
5.其实cnt[i]之和也是回文串的个数(废话?)
然后这道题怎么做呢?
跑一遍所有的节点,统计出所有回文串的权值(别忘了,每个回文串有cnt[i]个。。。)
下面就是代码

#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN=3e5+10;
const int N=26;
char str[MAXN];
struct Palindromic_Tree{
	int next[MAXN][N],fail[MAXN],cnt[MAXN],num[MAXN];
	int val[MAXN],state[MAXN],len[MAXN],S[MAXN];
	int last,n,p;
	int newnode(int l){
		for(int i=0;i<N;++i) next[p][i]=0;
		cnt[p]=0;
		state[p]=0;
		num[p]=0;
		len[p]=l;
		return p++;
	}
	void init(){
		p=0;
		newnode(0);
		newnode(-1);
		last=0;
		n=0;
		S[n]=-1;
		fail[0]=1;
	}
	int get_fail(int x){
		while(S[n-len[x]-1]!=S[n]) x=fail[x];
		return x;
	}
	int count_state(int x){
	    int res=0;
	    while(x){
            if(x&1) ++res;
            x>>=1;
	    }
        return res;
	}
	void add(int c){
		c-='a';
		S[++n]=c;
		int cur=get_fail(last);
		if(!next[cur][c]){
            int now=newnode(len[cur]+2);
			fail[now]=next[get_fail(fail[cur])][c];
            next[cur][c]=now;
            state[now]=state[cur]|(1<<c);
			num[now]=num[fail[now]]+1;
			val[now]=count_state(state[now]);
		}
		last=next[cur][c];
		cnt[last]++;
	}
	ll count_val(){
        for(int i=p-1;i>=2;--i) cnt[fail[i]]+=cnt[i];
        ll res=0;
        for(int i=2;i<p;++i) res+=(ll)cnt[i]*val[i];
        return res;
	}
}pt;
int main(){
    while(~scanf("%s",str)){
        pt.init();
        int len=strlen(str);
        for(int i=0;i<len;++i) pt.add(str[i]);
        printf("%lld\n",pt.count_val());
    }
    return 0;
}

回文树真的是回文串问题里面战斗机,只跑了30ms
溜了,刷专题去了555。。。

你可能感兴趣的:(Colorful String(The Preliminary Contest for ICPC Asia Xuzhou 2019)-回文树)