先贡献几个数据(没用别怪我):
/* ab 4 0 ab 1 ab 0 ab 1 ab abababac 4 0 aba 1 aba 0 abab 1 abab abcdefghijklmnopqrstuvwxyz 3 0 abc 1 def 1 jmn abcdabcd 3 0 cd 0 abcd 0 abcd */
思路:
因为要考虑不可重复和可重复,而且输入那一堆串还有重复的,如果可以重复,那么就是正常做法,回溯到根,全部相加;如果不可以重复,那么标记位置上的后缀串的长度。
ps:因为是书上例题,然后照着书上代码搞搞搞,没想到搞崩了。因为书上代码是错的!他开了一个flag表示这个位置是否存在后缀串,但是他找的时候= =、第一个错误;还有他没有把fail指针回溯到根,第二个错误,不过这个flag数组搞的很好?(其实并没有。。。贴第一发自己的,第二发书上已改正的代码)
MY CODE
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<queue> #include<string.h> #include<algorithm> using namespace std; typedef long long LL; typedef pair<int,int> PII; const int N=1e6+10; int g[600010][26],word[N],fail[N],sz; char txt[N],ss[N]; int ans[N][2],last[N],len[N],pos[100010],n,id[100010]; int flag[N]; int INS() { int p=0; int lens=strlen(ss); int index; for(int i=0;i<lens;i++){ index=ss[i]-'a'; if(g[p][index]==0){ memset(g[sz],0,sizeof(g[sz])); last[sz]=-1; flag[sz]=0; word[sz]=0; ans[sz][0]=ans[sz][1]=0; g[p][index]=sz++; } p=g[p][index]; } word[p]=1; flag[p]=1; len[p]=lens; return p; } void Build_fail() { int p=0; queue<int>que; for(int i=0;i<26;i++){ if(g[p][i]) { que.push(g[p][i]); fail[g[p][i]]=0; } } while(!que.empty()) { p=que.front();que.pop(); for(int i=0;i<26;i++){ int u=g[p][i]; if(!u) g[p][i]=g[fail[p]][i]; else{ que.push(u); int v=fail[p]; //取父节点的fail指针去匹配 while(v && !g[v][i]) v=fail[v]; fail[u]=g[v][i]; } } } } void solve() { int p=0; int index,lens=strlen(txt); for(int i=0;i<lens;i++) { index=txt[i]-'a'; p=g[p][index]; int temp=p; while(temp){ //回溯到根 if(word[temp]) { ans[temp][0]++; if((i-last[temp])>=len[temp]) { ans[temp][1]++; last[temp]=i; } } temp=fail[temp]; } } } int main() { int cas=1; while(~scanf("%s",txt)) { memset(g[0],0,sizeof(g[0])); sz=1; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%s",&id[i],ss); pos[i]=INS(); } Build_fail(); solve(); // for(int i=1;i<sz;i++) // printf("%d %d ",ans[i][0],ans[i][1]); printf("Case %d ",cas++); for(int i=1;i<=n;i++) printf("%d ",ans[pos[i]][id[i]]); puts(""); } return 0; }
BOOK CODE
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<queue> #include<string.h> #include<algorithm> using namespace std; typedef long long LL; typedef pair<int,int> PII; const int N=1e6+10; int g[600010][26],word[N],fail[N],sz; char txt[N],ss[N]; int ans[N][2],last[N],len[N],pos[100010],n,id[100010]; int flag[N]; int INS() { int p=0; int lens=strlen(ss); int index; for(int i=0;i<lens;i++){ index=ss[i]-'a'; if(g[p][index]==0){ memset(g[sz],0,sizeof(g[sz])); last[sz]=-1; flag[sz]=0; word[sz]=0; ans[sz][0]=ans[sz][1]=0; // fail[sz]=0; g[p][index]=sz++; } p=g[p][index]; } word[p]=1; flag[p]=1; len[p]=lens; return p; } void Build_fail() { int p=0; queue<int>que; for(int i=0;i<26;i++){ if(g[p][i]) { que.push(g[p][i]); fail[g[p][i]]=0; } } while(!que.empty()) { p=que.front();que.pop(); for(int i=0;i<26;i++){ int u=g[p][i]; if(!u) g[p][i]=g[fail[p]][i]; else{ que.push(u); fail[u]=g[fail[p]][i]; flag[u]|=flag[fail[u]]; } } } } void solve() { int p=0; int index,lens=strlen(txt); for(int i=0;i<lens;i++) { index=txt[i]-'a'; p=g[p][index]; int temp=p; while(temp&&!flag[temp]) temp=fail[temp]; while(temp){ if(word[temp]) { ans[temp][0]++; if((i-last[temp])>=len[temp]) { ans[temp][1]++; last[temp]=i; } } temp=fail[temp]; } } } int main() { int cas=1; while(~scanf("%s",txt)) { memset(g[0],0,sizeof(g[0])); sz=1; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%s",&id[i],ss); pos[i]=INS(); } Build_fail(); solve(); printf("Case %d ",cas++); for(int i=1;i<=n;i++) printf("%d ",ans[pos[i]][id[i]]); puts(""); } return 0; }