[USACO17DEC]Standing Out from the Herd

去年暑假做过,那时候只会打暴搜,被高中奆佬吊打。

后缀自动机万岁,再也不管后缀数组这辣鸡东西了

一、题目

点此看题

二、解法

本题需要用到一个知识点:广义 Sam \text{Sam} ,其实也没有多难,就是在一个新字符串插入时把 L a s t Last 赋值为 1 1 ,然后都按普通后缀自动机的方法做就行了。

插入完之后把每个串放进去匹配,对每个匹配到的点都暴力跳 p a r e n t parent 树,打上这个节点所有者的标记,如果所有者超过两个那就把这个节点的标记设为 1 -1 ,表示这个节点没有贡献,最后访问所有节点统计即可。

时间复杂度 O ( n ) O(n) ,贴个代码 q w q qwq

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 200005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,m,len[M],s[M];char c;
struct node
{
    int len,fa,ch[26];
    node() {memset(ch,0,sizeof ch);len=fa=0;}
};
struct automaton
{
    int cnt,last,val[M],ans[M];node a[M];
    automaton() {cnt=last=1;}
    void add(int c)
    {
        int p=last,np=last=++cnt;
        a[np].len=a[p].len+1;
        for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
        if(!p) a[np].fa=1;
        else
        {
            int q=a[p].ch[c];
            if(a[q].len==a[p].len+1) a[np].fa=q;
            else
            {
                int nq=++cnt;
                a[nq]=a[q];a[nq].len=a[p].len+1;
                a[q].fa=a[np].fa=nq;
                for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
            }
        }
    }
    void solve()
    {
        m=0;
        for(int i=1;i<=n;i++)
        {
            int now=1;
            for(int j=1;j<=len[i];j++)
            {
                now=a[now].ch[s[++m]];
                for(int p=now;val[p]!=-1 && val[p]!=i;p=a[p].fa)
                    if(val[p]==0)
                        val[p]=i;
                    else
                        val[p]=-1;
            }
        }
        for(int i=1;i<=cnt;i++)
            if(val[i]>0)
                ans[val[i]]+=a[i].len-a[a[i].fa].len;
        for(int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
}Sam;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        Sam.last=1;//广义后缀自动机核心操作
        while((c=getchar())!='\n' && c!=EOF)
        {
            c-= 'a';++len[i];
            s[++m]=c;
            Sam.add(c);
        }
    }
    Sam.solve();
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6732

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104156700