hdu 6599 I Love Palindrome String 回文自动机
hdu 6599 I Love Palindrome String 回文自动机
当个回文自动机的模板
题意
给一个串S,求长度为i的“特殊回文串”个数,“特殊回文串”要求是回文串,并且自己的一半也是回文串。
思路
求回文串个数相关,优先考虑使用回文自动机,“特殊回文串”要求是回文串,并且自己的一半也是回文串,显然就是fail树扒出来dfs搞一下,记录dfs路径上有没有长度一半的回文串即可。
PS:因为fail指针的意义是最长后缀回文,反过来路径显然是当前节点的回文后缀。
代码
#pragma comment (linker,"/STACK:102400000,102400000")
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define PB push_back
#define LL long long
#define pii pair<int,int>
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<<x<<endl;
#define FIO ios::sync_with_stdio(false);
#define ALL(x) x.begin(),x.end()
class PA {//回文自动机
private:
//fail 指针指向最长后缀回文状态,可以构建树
struct Node {
int len,cnt,ptr[26], fail; //必要时候 ptr 改成 map
Node(int len = 0) :cnt(0), len(len), fail(0) { memset(ptr, 0, sizeof(ptr)); }
};
vector<Node> nd;
vector<int> idx;
int cur; //当前指针停留的位置,即最后插入字符所对应的节点
string s;
int getfail(int x){
//沿着fail指针找到最长回文后缀(暴力)
while (s[s.size()-1-nd[x].len-1] != s[s.size()-1]) x = nd[x].fail;
return x;
}
void get_count(){//父亲统计cnt的时候加上儿子的
for(int i=nd.size()-1;i>=2;i--)
nd[nd[i].fail].cnt+=nd[i].cnt;
}
public:
PA() : cur(0){
nd.PB(Node(0));
nd[nd.size()-1].fail = 1;
nd.PB(Node(-1));
nd[nd.size()-1].fail = 0;
s="$";
}
void extend(char c) {
s += c;
int now = getfail(cur); //找到插入的位置
if (!nd[now].ptr[c - 'a']){
//若没有这个节点,则新建并求出它的fail指针
nd.PB(Node(nd[now].len + 2));
nd[nd.size()-1].fail = nd[getfail(nd[now].fail)].ptr[c - 'a']; //新节点的失败指针指向回文后缀
nd[now].ptr[c - 'a'] = nd.size()-1; //
}
cur = nd[now].ptr[c - 'a'];
idx.PB(cur);
++nd[cur].cnt;
}
int get_l(int x){//以x为右端点的最长回文子串的左端点
return x-nd[idx[x]].len+1;
}
void dfs(int x,vector<int> &ans,vector<vector<int>> &E,vector<int> &len,vector<int> &ok){
if(nd[x].len!=-1)len[nd[x].len]=1;
if(len[(nd[x].len+1)/2]) ok[x]=1;
for(int c:E[x])if(c!=0)dfs(c,ans,E,len,ok);
if(nd[x].len!=-1)len[nd[x].len]=0;
}
void addedge(int u,int v,vector<vector<int>> &E){E[u].PB(v);};
void get_ans(int n){
vector<int> ans(n+1,0);
vector<int> len(n+1,0);
vector<int> ok(nd.size(),0);
vector<vector<int>> E(nd.size());
for(int i=0;i<nd.size();i++)addedge(nd[i].fail,i,E);
dfs(0,ans,E,len,ok);
get_count();
for(int i=nd.size()-1;i>=2;i--)if(ok[i])ans[nd[i].len]+=nd[i].cnt;
for(int i=1;i<=n;i++) cout<<ans[i]<<" \n"[i==n];
}
};
int main(){
FIO;
string s;
while(cin>>s){
PA A;
for(char c:s) A.extend(c);
A.get_ans(s.size());
}
return 0;
}