bzoj 4460 : [Jsoi2013]广告计划

来源:互联网 发布:c语言为什么要加入指针 编辑:程序博客网 时间:2024/05/22 10:31

脑残一下午
首先,对于所有字符串建立后缀自动机
这里可以是广义后缀自动机或者狭义后缀自动机,我会给出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 20005using 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 20005using 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);        }    }}
0 0
原创粉丝点击