zoj3228

来源:互联网 发布:领航者炒股软件 编辑:程序博客网 时间:2024/06/06 01:58

这是一道很有意思的字符串的题。大部分的人都是用AC自动机过的。但是在看HH大神的博客的回复下面看到一种很有意思的解法。通常对于tire树的构造都是用字串构造。母串匹配。但是今天看到有人用母串构造tire树。但是这样构造需要一些前提。首先已经知道子串的最大的长度,其次这样的方法的构造不会MLE。开始的时候我用new node但是MLE了后来改为静态的方式构建tire就过了。我两种方法都写了一下。最开始写的是AC自动机,但是MLE了好久。最后将所有的状态hash了一下才过!!!真是!!

上代码:

(AC自动机版本)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
struct node{
    node *fail;
    node *next[26];
    int id;
    bool end;
    short tag;
    short len;
    node(){
        len=0;
        id=0;
        end=false;
        fail=NULL;
        for(int i=0;i<=25;i++){
            next[i]=NULL;
        }
        tag=-1;
    }
};
int in[100010];
int ff[100010];
const int MAXN=600010;
node* q[MAXN];
node *root=new node();
int num=1;
void insert(char word[],int flag,int k){
    node *cur=root;
    int i=0,branch;
    while(word[i]){
        branch=word[i]-'a';
        if(cur->next[branch]==NULL){
            cur->next[branch]=new node();
            cur->next[branch]->id=num++;
        }
        i++;
        cur=cur->next[branch];
    }
    in[k]=cur->id;
    cur->len=strlen(word);
    cur->end=true;
    if(cur->tag==-1)
        cur->tag=flag;
    else{
        if(cur->tag!=2){
            if(cur->tag!=flag)
                cur->tag=2;
        }
    }
}
void AC(){
int rear=1,front=0,i;
node *cur;
q[0]=root;
root->fail=NULL;
while(rear!=front){
cur=q[front++];
for(i=0;i<26;i++){
if(cur->next[i]!=NULL){
if(cur==root)
cur->next[i]->fail=root;
else{
node *ptr=cur->fail;
while(ptr!=NULL){
if(ptr->next[i]!=NULL){
cur->next[i]->fail=ptr->next[i];
//if(ptr->next[i]->end==true)
//cur->next[i]->end=true;
break;
}
ptr=ptr->fail;
}
if(ptr==NULL)cur->next[i]->fail=root;
}
q[rear++]=cur->next[i];
}
}
}
}
char s[100001];
char a[10];
int dp[100001][2];
int pos[100001][7];
int dpos[100001][7];
int hash[600010];
void search(){
    int i=0,ans=0;
    node *ptr=root;
    while(s[i]){
        int idx=s[i]-'a';
        while(ptr->next[idx]==NULL && ptr!=root)ptr=ptr->fail;
        ptr=ptr->next[idx];
        if(ptr==NULL)ptr=root;
        node *tmp=ptr;
        while(tmp!=NULL){
            if(tmp->tag==1 || tmp->tag==2){
                int cnt=0; int maxx=0,maxx1=0;
                for(int j=1;j<=6;j++){
                    if((i-pos[hash[tmp->id]][j])>=tmp->len && maxx<dpos[hash[tmp->id]][j]){
                        maxx=dpos[hash[tmp->id]][j];
                        cnt=j;
                    }
                    if((i-pos[hash[tmp->id]][j])<tmp->len && maxx1<dpos[hash[tmp->id]][j]){
                        maxx1=dpos[hash[tmp->id]][j];
                    }
                }
                if((maxx+1)>maxx1){
                dp[hash[tmp->id]][1]=max(dp[hash[tmp->id]][1],dpos[hash[tmp->id]][cnt]+1);
                if(dpos[hash[tmp->id]][6]>dpos[hash[tmp->id]][5]){
                    dpos[hash[tmp->id]][5]=dpos[hash[tmp->id]][6];
                }
                for(int j=2;j<=6;j++){
                    dpos[hash[tmp->id]][j]=dpos[hash[tmp->id]][j-1];
                    pos[hash[tmp->id]][j]=pos[hash[tmp->id]][j-1];
                }
                dpos[hash[tmp->id]][1]=dp[hash[tmp->id]][1];
                    pos[hash[tmp->id]][1]=i;
                }
                else
                    dp[hash[tmp->id]][1]=maxx1;


            }
                dp[hash[tmp->id]][0]++;
            tmp=tmp->fail;
        }
        i++;
    }
}
main(){
    int t=1;
    while(scanf("%s",s)!=-1){
        int n;num=1;
        root=new node();
        scanf("%d",&n);
        memset(hash,0,sizeof(hash));
        for(int i=1;i<=n;i++){
            int flag;
            scanf("%d",&flag);
            getchar();
            scanf("%s",a);
            insert(a,flag,i);
            ff[i]=flag;
            hash[in[i]]=i;
        }
        AC();
        root->id=0;
        memset(dp,0,sizeof(dp));
        memset(pos,0,sizeof(pos));
        memset(dpos,0,sizeof(dpos));
        search();
        printf("Case %d\n",t++);
        for(int i=1;i<=n;i++){
            printf("%d\n",dp[hash[in[i]]][ff[i]]);
        }
        printf("\n");
    }
}

(tire数版本)

#include<cstdio>
#include<cstring>
using namespace std;
struct node{
    int next[26];
    int overlap;
    int notoverlap;
    int pos;
};
node ww[1000000];
int num=0;
void ini(int k){
        ww[k].overlap=0;
        ww[k].notoverlap=0;
        ww[k].pos=-1;
        for(int i=0;i<=25;i++)
            ww[k].next[i]=-1;
}
void insert(char word[],int start){
    int cur=0;
    int i=0,branch;
    while(word[i]){
        branch=word[i]-'a';
        if(ww[cur].next[branch]==-1){
            num++;
            ini(num);
            ww[cur].next[branch]=num;
        }
        cur=ww[cur].next[branch];
        ww[cur].overlap++;
        if(ww[cur].pos<start){
            ww[cur].notoverlap++;
            ww[cur].pos=start+i;
        }
        i++;
    }
}
char a[100010];


main(){
    int t=1;
    while(scanf("%s",a)!=-1){
        int n;
        num=0;
        ini(0);
        for(int i=0;a[i];i++){
            char s[10];
            int j=0;
            for(j=0;j<=5 && a[i+j];j++){
                s[j]=a[i+j];
            }
            s[j]=0;
            insert(s,i);
        }
        printf("Case %d\n",t++);
        scanf("%d",&n);
        for(int i=0;i<=n-1;i++){
            int flag,ans[2],k=0,cnt=0;
            char s[10];
            scanf("%d %s",&flag,s);
            while(s[k]){
                int branch=s[k]-'a';
                if(ww[cnt].next[branch]!=-1){
                    cnt=ww[cnt].next[branch];
                    ans[0]=ww[cnt].overlap;
                    ans[1]=ww[cnt].notoverlap;
                }
                else{
                    break;
                }
                 k++;
            }
            if(k==strlen(s)){
                printf("%d\n",ans[flag]);
            }
            else{
                printf("0\n");
            }
        }
        printf("\n");
    }


}

原创粉丝点击