题意:
给一个原串,再给n个串,每个串有属性,属性0代表可以重叠,1代表不可以重叠
问每个串出现了多少次
思路:
为了方便建立两个自动机(0的一个,1的一个)
然后可以重叠的很好做,以前都做过
不可重叠的话需要记录两个东西
len[i]代表每个串的长度,used[i]代表每个串在之前出现的位置,初始化-1
然后遍历到的时候对于当前位置 j, 必须j>=used[i]+len[i] 才能算出现,并且更新
需要注意的是:
会出现同样属性并且相同的串。我处理的方式就是排序,按id排序大的在前
然后算一遍大的,用大的赋值给id 小的且串相同的。
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" using namespace std; char fuck[123456]; int ans[123456],used[123456],len[123456]; struct word { int x,id; char y[7]; } dc[123456]; struct trie { int mark; trie *next[27]; trie *fail; trie() { mark=0; memset(next,0,sizeof(next)); fail=NULL; } }; trie *root0,*root1; void init(int key,char *v,int id) { trie *p; if(key) p=root1; else p=root0; for(int i=0; v[i]; i++) { int tep=v[i]-'a'; if(p->next[tep]==NULL) p->next[tep]=new trie(); p=p->next[tep]; } p->mark=id; } void del(trie *p) { for(int j=0; j<26; j++) if(p->next[j]!=NULL) del(p->next[j]); free(p); } void getac() { queue<trie*>q; q.push(root0); while(!q.empty()) { trie *p,*tep; p=q.front(); q.pop(); for(int i=0; i<26; i++) { if(p->next[i]!=NULL) { if(p==root0) p->next[i]->fail=root0; else { tep=p->fail; while(tep!=NULL) { if(tep->next[i]!=NULL) { p->next[i]->fail=tep->next[i]; break; } tep=tep->fail; } if(tep==NULL) p->next[i]->fail=root0; } q.push(p->next[i]); } } } q.push(root1); while(!q.empty()) { trie *p,*tep; p=q.front(); q.pop(); for(int i=0; i<26; i++) { if(p->next[i]!=NULL) { if(p==root1) p->next[i]->fail=root1; else { tep=p->fail; while(tep!=NULL) { if(tep->next[i]!=NULL) { p->next[i]->fail=tep->next[i]; break; } tep=tep->fail; } if(tep==NULL) p->next[i]->fail=root1; } q.push(p->next[i]); } } } } void finde(char *v) { trie *p0=root0,*p1=root1; for(int i=0; v[i]; i++) { int tep=v[i]-'a'; while(p0->next[tep]==NULL && p0!=root0) p0=p0->fail; p0=p0->next[tep]; if(p0==NULL) p0=root0; trie *q0=p0; while(q0!=root0) { if(q0->mark!=0) ans[q0->mark]++; q0=q0->fail; } while(p1->next[tep]==NULL && p1!=root1) p1=p1->fail; p1=p1->next[tep]; if(p1==NULL) p1=root1; trie *q1=p1; while(q1!=root1) { if(q1->mark!=0) { if(i>=used[q1->mark]+len[q1->mark]) //不可重叠的判断 { ans[q1->mark]++; used[q1->mark]=i; } } q1=q1->fail; } } } int cmp(word a,word b) //排序的cmp { if(a.x==b.x) { if(strcmp(a.y,b.y)==0) { if(a.id>b.id) return 1; else return 0; } else { if(strcmp(a.y,b.y)>0) return 1; else return 0; } } else { if(a.x>b.x) return 1; else return 0; } } int main() { int cas=1; while(scanf("%s",fuck)!=-1) { int n; scanf("%d",&n); root0=new trie(); root1=new trie(); for(int i=1; i<=n; i++) { int x; char y[12]; scanf("%d%s",&x,y); len[i]=strlen(y); init(x,y,i); dc[i].x=x; strcpy(dc[i].y,y); dc[i].id=i; } memset(ans,0,sizeof(ans)); memset(used,-1,sizeof(used)); getac(); finde(fuck); sort(dc+1,dc+1+n,cmp); int i; for(i=1; dc[i+1].x==1; i++) //赋值给那些重复的 { if(strcmp(dc[i].y,dc[i+1].y)==0) ans[dc[i+1].id]=ans[dc[i].id]; } for(i=i+1; i<n; i++) { if(strcmp(dc[i].y,dc[i+1].y)==0) ans[dc[i+1].id]=ans[dc[i].id]; } printf("Case %d\n",cas++); for(int i=1; i<=n; i++) printf("%d\n",ans[i]); del(root0); del(root1); puts(""); } return 0; }
时间: 2024-10-10 20:09:00