hdu 5164 Matching on Array (奇葩版ac自动机)

来源:互联网 发布:淘宝卖化妆品 编辑:程序博客网 时间:2024/05/22 07:55

题意:

给出一个a序列,m个b序列,a能通过倍数关系能出现多少b串。例如a{ 2 4 8 } b{ 1 2 } 那么a中的{ 2 4 } 和{ 4 8 } 是可以通过b序列通过倍数变成的。

题解:

我们可以把串进行缩放,然后缩放后的串进行匹配。

对于m==1的情况用kmp 其他情况用ac自动机。搞一个分数类进行处理。自动机的边用map,对奇葩的地方就是这里,用map做边,map<Node,int>next[SIZE] 这样就通过map映射Node类型(分数类)来解决节点的存储关系。弄完这个,就是无脑的自动机匹配。可惜哥弄了一个晚上的代码最终以wa结尾。。。找啊找,各种原因,最终发现可能是cnt初始化为0的缘故,因为我的代码写法,会导致冲突!应为map如果不存对应的边,那么会返回0,同样根编号也是0,这样很明显冲突啊,所以各种wa!!!最后参照了别人的代码解决了这个问题。由于g++类无法存太大的数组,因此没写成类的形式。这题好题啊,出题人脑洞太大了,ORZ!

#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))typedef __int64 ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const int MOD=10007;const int maxn=110000;const int maxm=1000005;const int SIZE=1000005;int Next[maxm];//const int type=4;inline int gcd(int a,int b){    return b==0 ? a : gcd(b,a%b);}struct Node{    int up,down;    Node(){}    Node(int a,int b){        up=a;down=b;        int temp;        if(up>down)temp=gcd(up,down);        else temp=gcd(down,up);        up/=temp;        down/=temp;    }    bool operator==(const Node& a)const{        return up==a.up&&down==a.down;    }    bool operator!=(const Node& a)const{        return up!=a.up||down!=a.down;    }    bool operator<(const Node& a)const{        if(up!=a.up)            return up<a.up;        return down<a.down;    }}a[maxn],b[maxn];void input(Node buff[],int len){    int x,y;    scanf("%d",&x);    for(int i=1;i<len;i++){        scanf("%d",&y);        buff[i]=Node(y,x);        x=y;    }}map<Node,int>next[SIZE];int fail[SIZE],flag[SIZE];int cnt,root;int newNode(){    next[cnt].clear();    flag[cnt++]=0;    return cnt-1;}void Init(){    cnt=1;    root=newNode();}void Insert(Node buff[],int len){    int now=root;    Node k;    for(int i=1;i<=len;i++){        k=buff[i];        if(next[now][k]==0)            next[now][k]=newNode();        now=next[now][k];    }//for    flag[now]++;}void build(){    fail[root]=0;    Node k;    queue<int>Q;    ///注:next[now][i] <=> it->second ; i <=>it->first;    for(map<Node,int>::iterator it=next[root].begin();it!=next[root].end();++it){        fail[it->second]=root;        Q.push(it->second);    }//for    while(!Q.empty()){        int now=Q.front();Q.pop();        flag[now]+=flag[fail[now]];        for(map<Node,int>::iterator it=next[now].begin();it!=next[now].end();++it){            int temp=fail[now];            int nxt=next[temp][it->first];            while(temp&&!nxt){                temp=fail[temp];                nxt=next[temp][it->first];            }            if(temp) fail[it->second]=nxt;            else fail[it->second]=root;            Q.push(it->second);        }//for    }//while}ll Search(Node buff[],int len){    int now=root;    ll ans=0;    for(int i=1;i<=len;i++){        int nxt=next[now][buff[i]];        while(now&&!nxt){            now=fail[now];            nxt=next[now][buff[i]];        }        if(now) now=nxt;        else now=root;        ans+=flag[now];    }//for    return ans;}void get_next(Node T[],int len){    int i=0;    Next[i]=-1;    int j=-1;    while(i<len)    {        if(j==-1||T[i]==T[j]){            i++;j++;            Next[i]=j;        }else j=Next[j];    }}ll kmp(Node S[],Node T[],int lenS,int lenT){    ll ans=0;    int i=0,j=0;    while(i<lenS){        if(j==-1||S[i]==T[j]){            i++;            j++;        }else j=Next[j];        if(j==lenT) ans++;    }//for    return ans;}int main(){    int T,m,n,k;    ll ans;    scanf("%d",&T);    while(T--){        Init();        scanf("%d %d",&n,&m);        input(a,n);        ans=0;        if(m>1){            for(int i=1;i<=m;i++){                scanf("%d",&k);                input(b,k);                if(k>1) Insert(b,k-1);                else ans+=n;            }//for            build();            ans+=Search(a,n-1);        }else{            scanf("%d",&k);            input(b,k);            if(k>1){                get_next(b+1,k-1);                ans=kmp(a+1,b+1,n-1,k-1);            }else ans+=n;        }//else        printf("%I64d\n",ans);    }//while    return 0;}//main/**24 12 4 8 162 1 25 32 4 2 4 63 1 2 11 52 16 8*/



0 0
原创粉丝点击