题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5164
题意:
给出长度为n一个母串,给出m个长度为ki子串,匹配的条件是比率相同,如子串4 8 能和 1 2 4匹配。问所有子串在母串中出现多少次。
限制:
1 <= n,m <= 1e5
1 <= ki <= 300000
思路:
赤裸裸的ac自动机啊,不过next数组用map来实现,出题人脑洞真大。
这里有一点还要注意,hdu的g++,结构体里面不能开太大的东西,要不然他ce了还不告诉你,所以把ac自动机结构体里面的东西全搬到外面就可以了。
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
/*hdu 5164 Matching on Array 题意: 给出长度为n一个母串,给出m个长度为ki子串,匹配的条件是比率相同,如子串4 8 能和 1 2 4匹配。问所有子串在母串中出现多少次。 限制: 1 <= n,m <= 1e5 1 <= ki <= 300000 思路: 赤裸裸的ac自动机啊,不过next数组用map来实现,出题人脑洞真大。 这里有一点还要注意,hdu的g++,结构体里面不能开太大的东西,要不然他ce了还不告诉你,所以把ac自动机结构体里面的东西全搬到外面就可以了。 */ #include<iostream> #include<cstdio> #include<map> #include<algorithm> using namespace std; #define LL __int64 const int N=1000005; LL ans; int s[N],p[3*N]; int n,m,q; map<int,int> next[N]; map<int,int> :: iterator it; int que[N],head,tail; int cnt,root,null; int fail[N],end[N]; struct acm{ int newNode(){ next[cnt].clear(); end[cnt]=0; return cnt++; } void init(){ cnt=0; null=cnt++; root=newNode(); } void insert(int n){ int now=root; for(int i=0;i<n-1;++i){ int d=__gcd(p[i],p[i+1]); int t=p[i]/d*10001+p[i+1]/d; int nxt=next[now][t]; if(nxt==0) nxt=next[now][t]=newNode(); now=nxt; } ++end[now]; } void build(){ head=tail=0; fail[root]=null; for(it=next[root].begin();it!=next[root].end();++it){ fail[it->second]=root; que[tail++]=it->second; } while(head!=tail){ int now=que[head++]; end[now]+=end[fail[now]]; // for(it=next[now].begin();it!=next[now].end();++it){ int tmp=fail[now]; int nxt=next[tmp][it->first]; while(tmp!=null && !nxt){ tmp=fail[tmp]; nxt=next[tmp][it->first]; } if(tmp!=null) fail[it->second]=nxt; else fail[it->second]=root; que[tail++]=it->second; } } } void debug(){ for(int i=0;i<=cnt;i++){ printf("id=%3d,fail=%3d,sum=%3d\n",i,fail[i],end[i]); for(it=next[i].begin();it!=next[i].end();++it) printf("(%d,%d) ",it->first,it->second); puts(""); } } void query(int n){ int now=root; for(int i=0;i<n-1;++i){ int d=__gcd(s[i],s[i+1]); int t=s[i]/d*10001+s[i+1]/d; int nxt=next[now][t]; while(now!=null && !nxt){ now=fail[now]; nxt=next[now][t]; } if(now!=null) now=nxt; else now=root; //for(int j=now;j;j=fail[j]){ // ans+=end[j]; //} ans+=end[now]; } } }acm; int main(){ int T; scanf("%d",&T); while(T--){ ans=0; acm.init(); scanf("%d%d",&n,&q); for(int i=0;i<n;++i) scanf("%d",&s[i]); while(q--){ scanf("%d",&m); for(int i=0;i<m;++i) scanf("%d",&p[i]); if(m>1) acm.insert(m); else ans+=n; } acm.build(); //acm.debug(); acm.query(n); printf("%I64d\n",ans); } return 0; } |