题解

枚举所有的回文串
注意,本质不同的回文串最多只有 S |S| S
在这些回文串中,有一些是满足要求的,我们对这些串打上标记
首先跑一个 M a n a c h e r Manacher Manacher,然后枚举中间点,先从最大半径的回文串开始枚举,直到枚举的串之前出现过
在枚举的过程中, c h e c k check check 每个回文串是否满足要求,满足的打上标记,然后是最关键的部分,建图
根据枚举的顺序建立有向图,其实就是增加一条链
上面这个过程,用 H a s h Hash Hash 判断重复,复杂度是线性的
为什么要这样做?
例如,枚举到某一个中间点,它枚举的回文串如图

其中,满足条件的为绿色底***r> 每次枚举一个中间点,实际上就是增加一条链
我们在新加入的链的顶端 + 1 +1 +1 , 表明该顶点下面的所有儿子都将出现一次,其正确性是显然的
图全部建完之后,根据拓扑顺序,将每个顶点的值向儿子传递,同时保留自己的值
搞完之后,每个回文串出现的次数就已经确定了
最后一步,只关注之前打过标记的回文串,统计答案即可

代码

#include<bits/stdc++.h>
#define N 300010
#define M N<<0
#define INF 0x3f3f3f3f
#define eps 1e-10
// #define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%lld",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
gp_hash_table<LL,int>mp;
char x[N],ss[N<<1];
struct node{int x,y;}w[N];
int la[N],in[N],q[N],r[N<<1],len[N],num[N],fg[N],ans[N],lin_t,str_t,slen,cnt;
typedef pair<int,int> pi;
pi v[N<<1];
LL p[N],pp[N],hs[N],sh[N],hss[N],shh[N];

void pre(){
    slen=strlen(x+1); lin_t=cnt=0; mp.cl(); 
    memset(ans,0,sizeof(int)*(slen+3));
    for(int i=1;i<=slen;i++) 
        hs[i]=(hs[i-1]*1331+x[i])%mod,
        hss[i]=(hss[i-1]*9997+x[i])%P,
        sh[i]=(sh[i-1]*1331+x[slen-i+1])%mod,
        shh[i]=(shh[i-1]*9997+x[slen-i+1])%P;
}
inline void add(int x,int y){
    w[++lin_t]=node{y,la[x]};
    la[x]=lin_t;
}

inline LL cal(LL *h,LL *hh,int x,int y){
    LL t1=(h[y]-h[x-1]*p[y-x+1]%mod+mod)%mod,
       t2=(hh[y]-hh[x-1]*pp[y-x+1]%P+P)%P;
    return t1<<30|t2;
}
int Init(){
    int len=strlen(x+1);
    ss[0]='$';ss[1]='#';
    int j=2;
    for (int i=1;i<=len;i++)ss[j++]=x[i],ss[j++]='#';
    ss[j]='\0';
    return j;
}
void Manacher(){
    int len=Init();
    int p,mx=0;
    for (int i=1;i<len;i++)    {
        if (i<mx) r[i]=min(r[2*p-i],mx-i);else r[i]=1;
        while (ss[i-r[i]]==ss[i+r[i]]) r[i]++;
        if (mx<i+r[i])p=i,mx=i+r[i];
    }
    str_t=0;
    for (int i=2;i<len;i++)    {
        if (ss[i]=='#' && r[i]==1) continue;
        int x=i/2-r[i]/2+1,y=i/2+r[i]/2-!(i&1);
        v[str_t++]=pi(x,y);
        
    }
    for(int i=0;i<len+3;i++) r[i]=0;
}


inline bool check(int l,int r){
    if (cal(hs,hss,l,r)!=cal(sh,shh,slen-r+1,slen-l+1)) return false;
    if (cal(hs,hss,l,(l+r)>>1)!=cal(sh,shh,slen+1-((l+r)>>1),slen+1-l)) return false;
    return true;
}
namespace IO{ 
 struct Ostream_fwrite{ 
      #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 
        char *buf,*p1,*pend; 
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;} 
        void out(char ch){ 
            if (p1==pend){ 
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf; 
            } 
            *p1++=ch; 
        } 
        void print(int x){ 
            static char s[15],*s1;s1=s; 
            if (!x)*s1++='0';if (x<0)out('-'),x=-x; 
            while(x)*s1++=x%10+'0',x/=10; 
            while(s1--!=s)out(*s1); 
        } 
        void print(char *s){while (*s)out(*s++);} 
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
        ~Ostream_fwrite(){flush();} 
    }Ostream; 
    inline void print(int x){Ostream.print(x);} 
    inline void print(char *s){Ostream.print(s);} 
    inline void flush(){Ostream.flush();}
};
using namespace IO;
int main(){

    p[0]=1; pp[0]=1;
    for(int i=1;i<N;i++) p[i]=p[i-1]*1331%mod,
                         pp[i]=pp[i-1]*9997%P;
    while(~scanf("%s",x+1))
    {
        pre();  
        Manacher();
        for(int i=0;i<str_t;i++){
            int l=v[i].fi,r=v[i].se,k=0;
            while(l<=r){
                LL tm=cal(hs,hss,l,r);
                int t=mp[tm];
                if(t){ q[++k]=t; break;}
                mp[tm]=++cnt;
                q[++k]=cnt;
                if (check(l,r)) fg[cnt]=1;
                len[cnt]=r-l+1;
                l++;r--;
            }
            if (k) num[q[1]]++;
            for(int i=1;i<k;i++) add(q[i],q[i+1]),in[q[i+1]]++;
        }
        int t=0,   h=0;
        for(int i=1;i<=cnt;i++) if (!in[i]) q[++t]=i;
        while(h<t){
            h++; int x=q[h];
            for(int j=la[x];j;j=w[j].y){
                num[w[j].x]+=num[x];
                in[w[j].x]--; if (!in[w[j].x]) q[++t]=w[j].x;
            }
        }

        for (int i=1;i<=cnt;i++) if (fg[i]) ans[len[i]]+=num[i];
        print(ans[1]);
        for (int i=2;i<=slen;i++) 
            Ostream.out(' '),print(ans[i]); 
            Ostream.out('\n');

        for(int i=1;i<=cnt;i++) in[i]=num[i]=la[i]=len[i]=fg[i]=0;
    }
}