lcrtest的博客

一个SC蒟蒻的blog

bzoj 4460 : [Jsoi2013]广告计划

脑残一下午
首先,对于所有字符串建立后缀自动机
这里可以是广义后缀自动机或者狭义后缀自动机,我会给出2份代码
然后是匹配时间
我们枚举答案,问题变成一个答案是否能够被成功匹配
观察发现,如果当前答案为ans,那么11+ans1+ans2......都会在一排一起出现
同理 22+ans2+ans2......也会这样
我们定义have[i][j]表示ii+ansi+ans2......是否在第j列出现
这个可以在后缀自动机上求right集合实现
那么ans什么情况会成为答案呢?
我们观察样例,have[1][2]have[2][3]have[3][3]同时存在的时候,ans为答案
结论:ans为答案,仅当存在一个x,使得have[1][x]have[2][x]have[3][x]....have[ans][x]同时存在,但是存在例外:x有一次机会在中间某个地方+1
然后暴力跑就好了,由于我复杂度没有卡满所以跑得飞快QAQ
顺便说一句,两份代码统计right的方法是一样的,可以互换,但是有基数排序的方法
代码
狭义后缀自动机

#include<bits/stdc++.h>
#define N 20005
using namespace std;
namespace sam{
    int last=1,tot=1;
    int t[N][27],pre[N],val[N],deep[N];
    bitset<102>right[N];
    void insert(int x,int ps){
        int np=++tot,now=last;last=np;val[tot]=1;
        deep[np]=deep[now]+1;right[np][ps]=1;
        while(now&&!t[now][x]){
            t[now][x]=np;now=pre[now];
        }
        if(!now)pre[np]=1;
        else{
            int q=t[now][x],p=now;
            if(deep[p]+1==deep[q])pre[np]=q;
            else{
                int nq=++tot;deep[nq]=deep[p]+1;
                pre[nq]=pre[q];pre[np]=pre[q]=nq;
                memcpy(t[nq],t[q],sizeof t[q]);right[nq]=right[q];
                while(now&&t[now][x]==q)t[now][x]=nq,now=pre[now];
            }
        }
    }
    struct node{
        int id,x;
        friend bool operator < (const node &a,const node &b){
            return a.x<b.x;
        }
    }s[N];
    void add(){
        for(int i=1;i<=tot;i++)s[i]=(node){i,deep[i]};
        sort(s+1,s+tot+1);
        for(int i=tot;i>=2;i--){
            right[pre[s[i].id]]|=right[s[i].id];
        }
    }
}
char p[205];
int n,m,len;
bitset<102>have[205];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",p+1);
        for(int j=1;j<=m;j++){
            sam::insert(p[j]-'a',j);
        }
        sam::insert(26,0);
    }
    sam::add();
    scanf("%s",p+1);len=strlen(p+1);
    for(int ans=1;ans<=len;ans++){
        for(int j=1;j<=ans;j++){
            int x=1,y=j,f=0;
            while(y<=len){
                x=sam::t[x][p[y]-'a'];
                y=y+ans;f++;
            }
            have[j]=sam::right[x]>>(f-1);
        }
        for(int i=1;i<=m;i++){
            if(!have[1][i])continue;
            int a=1,b=1;
            for(int j=2;j<=ans;j++){
                b=(a|b)&&have[j][i+1];
                a&=have[j][i];
                if((!a)&&(!b))break;
            }
            if(a|b)cout<<ans<<endl,exit(0);
        }
    }
}

广义后缀自动机

#include<bits/stdc++.h>
#define N 20005
using namespace std;
namespace sam{
    int last=1,tot=1;
    int t[N][27],pre[N],val[N],deep[N];
    bitset<102>right[N];
    void insert(int x,int ps){
        if(t[last][x]){
            last=t[last][x];right[x][ps]=1;return;
        }
        int np=++tot,now=last;last=np;val[tot]=1;
        deep[np]=deep[now]+1;right[np][ps]=1;
        while(now&&!t[now][x]){
            t[now][x]=np;now=pre[now];
        }
        if(!now)pre[np]=1;
        else{
            int q=t[now][x],p=now;
            if(deep[p]+1==deep[q])pre[np]=q;
            else{
                int nq=++tot;deep[nq]=deep[p]+1;
                pre[nq]=pre[q];pre[np]=pre[q]=nq;
                memcpy(t[nq],t[q],sizeof t[q]);right[nq]=right[q];
                while(now&&t[now][x]==q)t[now][x]=nq,now=pre[now];
            }
        }
    }
    int nxt[N],fir[N],to[N],Sz;
    void add(int x,int y){
        nxt[++Sz]=fir[x];fir[x]=Sz;to[Sz]=y;
    }
    void dfs(int x){
        for(int u=fir[x];u;u=nxt[u]){
            dfs(to[u]);right[x]|=right[to[u]];
        }
    }
    void add(){
        for(int i=2;i<=tot;i++)add(pre[i],i);
        dfs(1);
    }
}
char p[205];
int n,m,len;
bitset<102>have[205];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",p+1);
        for(int j=1;j<=m;j++){
            sam::insert(p[j]-'a',j);
        }
        sam::last=1;
    }
    sam::add();
    scanf("%s",p+1);len=strlen(p+1);
    for(int ans=1;ans<=len;ans++){
        for(int j=1;j<=ans;j++){
            int x=1,y=j,f=0;
            while(y<=len){
                x=sam::t[x][p[y]-'a'];
                y=y+ans;f++;
            }
            have[j]=sam::right[x]>>(f-1);
        }
        for(int i=1;i<=m;i++){
            if(!have[1][i])continue;
            int a=1,b=1;
            for(int j=2;j<=ans;j++){
                b=(a|b)&&have[j][i+1];
                a&=have[j][i];
                if((!a)&&(!b))break;
            }
            if(a|b)cout<<ans<<endl,exit(0);
        }
    }
}

阅读更多
版权声明:233333333333333333333333333333333333333333 https://blog.csdn.net/lcrtest/article/details/51509541
文章标签: 题解
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭