1. 程式人生 > >【[USACO17DEC]Standing Out from the Herd】

【[USACO17DEC]Standing Out from the Herd】

題目

不會廣義\(SAM\)

但信仰插入特殊字元就可以搞定一切了

我們先把所有的串搞在一起建出一個\(SAM\),記得在中間插入特殊字元

對於\(parent\)樹上的一個節點,只有當其\(endpos\)集合中的所有元素都來自於同一個串的時候我們才對它進行統計

所以我們需要維護一個\(parent\)樹上子樹最大值和最小值,這樣我們就能很快的判斷這個\(endpos\)是否合法了

但是非常棘手的一類情況是我們插進去的特殊字元,顯然\(SAM\)裡有一些奇奇怪怪的子串中含有特殊字元

那也好辦,我們存好每個串的起始位置只要那些沒有跨越特殊字元的就好了

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 200005
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
struct E{int v,nxt;} e[maxn];
char S[maxn];
int m,n,lst=1,cnt=1,num;
int len[maxn],fa[maxn],son[maxn][27],mx[maxn],ml[maxn];
int f[maxn],head[maxn],d[maxn],Ans[maxn],li[maxn];
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs(int x) {
    for(re int i=head[x];i;i=e[i].nxt) 
        dfs(e[i].v),mx[x]=max(mx[e[i].v],mx[x]),ml[x]=min(ml[e[i].v],ml[x]),d[x]|=d[e[i].v];
}
inline void ins(int c,int o)
{
    int f=lst,p=++cnt; lst=p;
    len[p]=len[f]+1,mx[p]=ml[p]=o;
    if(c==26) d[p]=1;
    while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    if(!f) {fa[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {fa[p]=x;return;}
    int y=++cnt;
    len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    for(re int i=0;i<27;i++) son[y][i]=son[x][i];
    while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int main()
{
    memset(ml,20,sizeof(ml));
    scanf("%d",&m);
    for(re int i=1;i<=m;i++)
    {
        scanf("%s",S+1);
        int len=strlen(S+1);li[i]=n+1;
        for(re int j=1;j<=len;j++) ins(S[j]-'a',++n),f[n]=i;
        ins(26,++n);
    }
    for(re int i=2;i<=cnt;i++) add(fa[i],i);
    dfs(1);
    for(re int i=2;i<=cnt;i++)
    {
        if(d[i]) continue;
        if(f[mx[i]]!=f[ml[i]]) continue;
        int minlen=len[fa[i]]+1;
        if(f[mx[i]-minlen+1]!=f[mx[i]]) continue;
        if(f[mx[i]-len[i]+1]==f[mx[i]]) Ans[f[mx[i]]]+=len[i]-len[fa[i]];
            else Ans[f[mx[i]]]+=mx[i]-li[f[mx[i]]]-minlen+2;
    }
    for(re int i=1;i<=m;i++) printf("%d\n",Ans[i]);
    return 0;
}