2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp

来源:互联网 发布:女童白色运动鞋淘宝 编辑:程序博客网 时间:2024/06/05 05:17

https://vjudge.net/contest/177933#overview

H HDU3068

做法:马拉车模板

#include <bits/stdc++.h>using namespace std;const int maxn= 110015;char s[maxn];char str[maxn*2];int  dp[maxn*2];int mlc(){    int n=strlen(s+1);    str[0]='@';    for(int i=2;i<=2*n;i+=2)    {        str[i-1] = '#' ;        str[i]=s[i/2] ;    }    str[2*n+1] = '#';    str[2*n+2] = '0';    str[2*n+3] = 0;    memset(dp,0,sizeof(dp));    int ans=0 ,mx=0,id=0;    for(int i=1;i<=2*n+1;++i)    {        mx>i? dp[i]=min(dp[2*id-i],mx-i) :dp[i]=1 ;        while(str[i-dp[i]] == str[i+dp[i]]) dp[i]++;        if(dp[i]+i>mx)        {            mx=dp[i]+i;            id=i;        }        ans=max(ans,dp[i]);    }    return ans-1;}int main(){    while(scanf("%s",s+1)!=EOF)    {        printf("%d\n",mlc());    }    return 0;}

POJ 2406

做法: KMP  最小循环节 N-NEXT[N] 前提(N%(N-NEXT[N])==0)

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;const int maxn=1e6+10;char s[maxn];int next[maxn];int len;void getnext(){    int j,k;    j=0;  next[0] =  k =-1;    while(j<len)    {        if(k==-1 || s[j]==s[k]) next[++j]=(++k);        else  k=next[k];    }}int main(){    while(scanf("%s",s)!=EOF)    {        if(s[0]=='.') break;        len=strlen(s);        getnext();        int temp = len-next[len];        if(len%temp==0)        {            printf("%d\n",len/temp);        }        else        {            printf("1\n");        }    }    return 0;}

HDU 2222

做法:AC自动机模板

#include <bits/stdc++.h>using namespace std;struct trie{    int next[500010][26],fail[500010],end[500010];    int root , tot;    int newnode()    {        for(int i=0;i<26;++i)        {            next[tot][i]=-1;        }        end[tot++] = 0;        return tot-1;    }    void init()    {        tot=0;        root = newnode();    }    void push(char str[])    {        int len=strlen(str);        int now=root;        for(int i=0;i<len;++i)        {            if(next[now][str[i]-'a']== -1)            {                next[now][str[i]-'a'] = newnode();            }            now = next[now][str[i]-'a'];        }        end[now]++;    }    void build()    {        queue<int> que;        fail[root] = root;        for(int i=0;i<26;++i)        {            if(next[root][i]==-1) next[root][i]=root;            else            {                fail[next[root][i]]=root;                que.push(next[root][i]);            }        }        while(!que.empty())        {            int now=que.front() ; que.pop();            for(int i=0;i<26;++i)            {                if(next[now][i]==-1)                {                    next[now][i]=next[fail[now]][i];                }                else                {                    fail[next[now][i]]=next[fail[now]][i];                    que.push(next[now][i]);                }            }        }    }    int query(char str[])    {        int len=strlen(str);        int now=root;        int ans=0;        for(int i=0;i<len;++i)        {            now= next[now][str[i]-'a'];            int temp = now;            while(temp!=root)            {                ans+=end[temp];                end[temp]=0;                temp=fail[temp];            }        }        return ans;    }}ac;char s[1000010];int main(){    int T,n;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        ac.init();        for(int i=0;i<n;++i)        {            scanf("%s",s);            ac.push(s);        }        ac.build();        scanf("%s",s);        printf("%d\n",ac.query(s));    }    return 0;}

POJ 2778

做法:只需要把病毒串标记。然后对没有标记在矩阵上记录权值(如果next节点不存在也要记录),套一个矩阵快速幕即可!

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;typedef long long ll;const ll mod =1e5;struct matirx{     ll mu[105][105];     matirx()     {         for(int i=0;i<105;++i)         {             for(int j=0;j<105;++j)             {                 mu[i][j]=0;             }         }     }};int turn(char c){    if(c=='A') return 0;    if(c=='G') return 1;    if(c=='C') return 2;    if(c=='T') return 3;}struct tire{    int next[105][4],fail[105],end[105];    int root,tot;    int newnode()    {        for(int i=0;i<4;++i)        {            next[tot][i]=-1;        }        end[tot++]=0;        return tot-1;    }    void init()    {        tot=0;       root=newnode();    }    void push(char str[])    {        int len=strlen(str);        int now=root;        for(int i=0;i<len;++i)        {            if(next[now][turn(str[i])]==-1)            {                next[now][turn(str[i])] = newnode();            }            now=next[now][turn(str[i])];        }        end[now]=1;    }    void build()    {        queue<int> que;        fail[root] = root;        for(int i=0;i<4;++i)        {            if(next[root][i]==-1)            {                next[root][i]=root;            }            else            {                fail[next[root][i]] = root;                que.push(next[root][i]);            }        }        while(!que.empty())        {             int now=que.front() ;que.pop();             if(end[fail[now]]) end[now]=1;             for(int i=0;i<4;++i)             {                 if(next[now][i]==-1)                 {                     next[now][i]=next[fail[now]][i];                 }                 else                 {                     fail[next[now][i]] = next[fail[now]][i];                     que.push(next[now][i]);                 }             }        }    }}ac;matirx muilt(matirx a ,matirx b){    matirx ans;    for(int i=0;i<ac.tot;++i)    {        for(int k=0;k<ac.tot;++k)        {            for(int j=0;j<ac.tot;++j)            {                ans.mu[i][j] = ( ans.mu[i][j] + a.mu[i][k] * b.mu[k][j] )%mod;;            }        }    }    return ans;}matirx pow(matirx bit ,ll n){    matirx ans;    for(int i=0;i<ac.tot;++i) ans.mu[i][i]=1;    while(n)    {        if( n & 1) ans = muilt(ans,bit);        bit = muilt(bit,bit);        n>>=1;    }    return ans;}matirx getbit(){    matirx x;    for(int i=0;i<ac.tot;++i)    {        for(int j=0;j<4;++j)        {            if(!ac.end[ac.next[i][j]])            {                x.mu[i][ac.next[i][j]]++;            }        }    }    return x;}char s[100500];int main(){    int n;    ll m;    while(scanf("%d%I64d",&n,&m)!=EOF)    {        ac.init();        for(int i=0;i<n;++i)        {            scanf("%s",s);            ac.push(s);        }        ac.build();        matirx bit = getbit();        matirx ans = pow(bit,m);        ll sum=0;        for(int i=0;i<ac.tot;++i)        {            sum = (sum+ans.mu[0][i])%mod;        }        printf("%lld\n",sum);    }    return 0;}

HDU 2852

做法:AC自动机 + 状压dp

AC自动机上维护状态转移,对每个key进行表号,并用s表示,注意如果fail链指向标记也要进行标记

#include <bits/stdc++.h>using namespace std;int n,m,k;int num[1<<12];int dp[30][105][1<<12];const int mod=20090717;struct tire{     int next[105][26] , end[105] ,fail[105];     int tot,root;     int newnode()     {         for(int i=0;i<26;++i) next[tot][i]=-1;         end[tot++]=0;         return tot-1;     }     void init()     {         tot=0;         root = newnode();     }     void pusuh(char s[],int cnt)     {         int len=strlen(s);         int now=root;         for(int i=0;i<len;++i)         {             if(next[now][s[i]-'a']==-1) next[now][s[i]-'a'] = newnode();             now = next[now][s[i]-'a'];         }         end[now]|=(1<<cnt);     }     void build()     {         fail[root]=root;         queue<int> que;         for(int i=0;i<26;++i)         {            if(next[root][i]==-1) next[root][i] = root;            else            {                 fail[next[root][i]] = root;                 que.push(next[root][i]);            }         }         while(!que.empty())         {             int now=que.front(); que.pop();             end[now]|=end[fail[now]];             for(int i=0;i<26;++i)             {                 if(next[now][i]==-1)                 {                     next[now][i]=next[fail[now]][i];                 }                 else                 {                     fail[next[now][i]] = next[fail[now]][i];                     que.push(next[now][i]);                 }             }         }     }     int work()    {       for(int i=0;i<=n;++i)       {           for(int j=0;j<tot;++j)           {               for(int k=0;k<(1<<m);++k)               {                   dp[i][j][k]=0;               }           }       }       dp[0][0][0]=1;       for(int i=0;i<n;++i)       {           for(int j=0;j<tot;++j)           {               for(int k=0;k<(1<<m);++k)               {                   if(!dp[i][j][k]) continue;                    for(int t=0;t<26;++t)                   {                       dp[i+1][next[j][t]][k|end[next[j][t]]] = ( dp[i+1][next[j][t]][k|end[next[j][t]]]+dp[i][j][k] )%mod;                   }               }           }       }       int ans=0;       for(int i=0;i<(1<<m);++i)       {           if(num[i]<k) continue;           for(int j=0;j<tot;++j)                ans= (ans+dp[n][j][i])%mod;       }       return ans;    }}ac;char s[105];int main(){    memset(num,0,sizeof(num));    for(int i=0;i<(1<<10);++i)    {        for(int j=0;j<10;++j)        {            if(i&(1<<j)) num[i]++;        }    }    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        if(n==0&&m==0&&k==0) break;        ac.init();        for(int i=0;i<m;++i)        {            scanf("%s",s);            ac.pusuh(s,i);        }        ac.build();        printf("%d\n",ac.work());    }    return 0;}


HDU 2774
做法:后缀数组:将两个串放在一起,然后在中间加一个标记即可。答案就在 rank排名的交界处 ,一定要满足两个sa在不同的串内, 然后求最大的height

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int maxn=5e5+10;char s1[maxn],s2[maxn],s[maxn<<1];int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];int rk[maxn],height[maxn];void getsa(int n,int m){    int *x=t1,*y=t2;    for(int i=0;i<m;++i) c[i]=0;    for(int i=0;i<n;++i) c[x[i]=s[i]]++;    for(int i=1;i<m;++i) c[i]+=c[i-1];    for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;    for(int k=1;k<=n;k<<=1)    {        int p=0;        for(int i=n-k;i<n;++i) y[p++]=i;        for(int i=0;i<n;++i)        if(sa[i]>=k)  y[p++] = sa[i]-k;        for(int i=0;i<m;++i) c[i]=0;        for(int i=0;i<n;++i) c[x[y[i]]]++;        for(int i=1;i<m;++i) c[i]+=c[i-1];        for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];        swap(x,y);        p=1;    x[sa[0]]=0;        for(int i=1;i<n;++i)        x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;        if(p>=n) break;        m=p;    }}void gethight(int n){    int k=0;    for(int i=0;i<n;++i) rk[sa[i]]=i;    for(int i=0;i<n;++i)    {        if(k) k--;        else k=0;        int j=sa[rk[i]-1];        while(s[i+k]==s[j+k]) k++;        height[rk[i]]=k;    }}int main(){    while(scanf("%s%s",s1,s2)!=EOF)    {        int pos=0;        for(int i=0;s1[i];++i) s[pos++] = s1[i]-'a'+1;        s[pos++]=28;        for(int i=0;s2[i];++i) s[pos++] = s2[i]-'a'+1;        s[pos++]=0;        getsa(pos,29);        gethight(pos);        int ans=0, len = strlen(s1);        for(int i=2;s[i];++i)        {            if(height[i]>ans)            {                if(sa[i-1]>=0 &&sa[i-1]<len&&len<sa[i]) ans=height[i];                if(0<=sa[i] && sa[i]<len &&len<sa[i-1]) ans=height[i];            }        }        printf("%d\n",ans);    }    return 0;}


POJ 3261
求重复k次以上的最长重复子串
做法:套完板子之后,二分答案,将heigh大于mid的分为一组如果有超过k个则检验成功

板子使用注意一些地方

getsa(n+1,maxn+2);

m基数取比最大的数稍大即可。最后串加个s[N]=0; hight是从2开始的!!!
#include <iostream>#include <cstring>#include <cstdio>#include <queue>using namespace std;const int maxn=20010;int s[maxn<<1];int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];int rk[maxn],height[maxn];void getsa(int n,int m){    int *x=t1,*y=t2;    for(int i=0;i<m;++i) c[i]=0;    for(int i=0;i<n;++i) c[x[i]=s[i]]++;    for(int i=1;i<m;++i) c[i]+=c[i-1];    for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;    for(int k=1;k<=n;k<<=1)    {        int p=0;        for(int i=n-k;i<n;++i) y[p++]=i;        for(int i=0;i<n;++i)        if(sa[i]>=k)  y[p++] = sa[i]-k;        for(int i=0;i<m;++i) c[i]=0;        for(int i=0;i<n;++i) c[x[y[i]]]++;        for(int i=1;i<m;++i) c[i]+=c[i-1];        for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];        swap(x,y);        p=1;    x[sa[0]]=0;        for(int i=1;i<n;++i)        x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;        if(p>=n) break;        m=p;    }}void gethight(int n){    int k=0,j;    for(int i=0;i<=n;++i) rk[sa[i]]=i;    for(int i=0;i<n;++i)    {        if(k) k--;        j=sa[rk[i]-1];        while(s[i+k]==s[j+k]) k++;        height[rk[i]]=k;    }}bool judge(int mid,int n,int kk){    int num=1;    for(int i=2;i<=n;++i)    {        if(height[i]>=mid)        {            num++;            if(num>=kk) return 1;        }        else num=1;    }    return 0;}int main(){    int n,kk;    while(scanf("%d%d",&n,&kk)!=EOF)    {        int maxn=0;        for(int i=0;i<n;++i)  { scanf("%d",&s[i]); maxn=max(maxn,s[i]);}        s[n]=0;        getsa(n+1,maxn+2);        gethight(n);        int l=0,r=n;        int ans=0;        while(l<=r)        {            int mid=(l+r)>>1;            if(judge(mid,n,kk)) {ans = max(ans,mid); l=mid+1;}            else r=mid-1;        }        printf("%d\n",ans);    }    return 0;}






原创粉丝点击