题目
题意:
有一些压缩模式串和压缩主串,展开后问有多少个模式串在主串里,注意若两个模式串都在主串内,且一个包含另一个,则只算一次。
解法:
展开后,用模式串建AC自动机,然后用主串跑一次看有哪些包含在内,然后将模式串连在一次,再跑一次看有哪些包含,然后减去就可以啦。
TIme:469ms Memory:47836KB Length:3327B #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <map> #include <queue> #include <set> #define PI 3.1415926535898 #define INF 1000000000 #define MAXM 300010 #define MP(x,y) (make_pair((x),(y))) using namespace std; struct Node{ int cnt,h,len; int next[27],fail; void init() { h=0; cnt = 0; fail = -1; memset(next,-1,sizeof(next)); } }trie[MAXM]; char str[5100005],tstr[5100005],sub[2505*1205]; int cnt,ans,subl,pos[2505],total; vector<int> tpos,tcnt; short ssub[2505*1205]; bool vi[2505]; void insert(char str[],int h) { int p=0,x; for(int i=0;str[i];i++) { x=str[i]-'A'; if(trie[p].next[x]==-1) { trie[++cnt].init(); trie[p].next[x]=cnt; } p=trie[p].next[x]; } trie[p].cnt++; trie[p].h=h; trie[p].len=strlen(str); pos[h]=p; } void build_ac() { queue<int> q; int root=0; q.push(0); while(!q.empty()) { int p=q.front(); int temp=0; q.pop(); for(int i=0;i<26;i++) { int child=trie[p].next[i]; if(child!=-1) { if(p==root) trie[child].fail=root; else { temp=trie[p].fail; while(temp!=-1) { if(trie[temp].next[i]!=-1) { trie[child].fail=trie[temp].next[i]; break; } temp=trie[temp].fail; } if(temp==-1) trie[child].fail=root; } q.push(child); } } } } int query(char str[],int ty) { int index,len,result,root=0; int p=root; result=0; len=strlen(str); for(int i=0;i<len;i++) { index=str[i]-'A'; while(trie[p].next[index]==-1&&p!=root) p=trie[p].fail; p=trie[p].next[index]; if(p==-1) p=root; int temp=p; while(temp!=root&&trie[temp].cnt!=-1) { result+=trie[temp].cnt; bool flag=0; if(ty==0) { int tt=i-trie[temp].len+1; if(tt>=0&&ssub[tt]==ssub[i]&&ssub[tt]!=trie[temp].h&&vi[ssub[tt]]==1) { if(trie[temp].h&&vi[trie[temp].h]) vi[trie[temp].h]=0,--total; } else flag=1; } tpos.push_back(temp); tcnt.push_back(trie[temp].cnt); if(flag==0) trie[temp].cnt=-1; if(ty==1) vi[trie[temp].h]=1; temp=trie[temp].fail; } } return result; } void change(char tstr[]) { int j = 0; for(int i = 0;tstr[i];i++) { if(tstr[i]>='A'&&tstr[i]<='Z') str[j++]=tstr[i]; else if(tstr[i]=='[') { int num = 0; while(tstr[++i]>='0'&&tstr[i]<='9') { num = num*10+tstr[i]-'0'; } char tmp; for(;tstr[i]!=']';i++) tmp = tstr[i]; for(int k = 0; k < num;k++) str[j++]=tmp; } } str[j]='\0'; } void add(char s[],int h) { for(int i=0;s[i];++i,++subl) sub[subl]=s[i],ssub[subl]=h; } int main() { //freopen("J:\\MyDocument\\Code\\input.txt","r",stdin); int ca,n; scanf("%d",&ca); while(ca--) { subl=0; trie[0].init(); scanf("%d",&n); cnt = 0; for(int i = 0; i < n; i++) { scanf("%s",tstr); change(tstr); add(str,i+1); insert(str,i+1); } build_ac(); tpos.clear(),tcnt.clear(); memset(vi,0,sizeof(vi)); scanf("%s",tstr); change(tstr); total=query(str,1); for(int i=0;i<tpos.size();++i) trie[tpos[i]].cnt=tcnt[i]; sub[subl]='\0'; query(sub,0); printf("%d\n",total); } }