还是统计串问题,只是分成了同一种串允许互相覆盖和不允许互相覆盖两种情况。
对于允许互相覆盖的情况,就是模版了。对于不允许覆盖的情况,只要记录下该串最后一次出现并且被统计的位置即可,能统计的条件是lasp[id]+len[id]<=pos。
#include <string.h> #include <stdio.h> #define MAXL 600001 #define MAXN 100001 #define INF 0x3fffffff char s[MAXN],s1[10]; int n,type,stp[MAXN],sps[MAXN]; int next[MAXL][26],fail[MAXL],flag[MAXL],lent[MAXL],lasp[MAXL],ans[MAXL][2],pos; int newnode(){ for(int i=0;i<26;i++)next[pos][i]=0; flag[pos]=fail[pos]=0; return pos++; } void insert(char *s,int type,int sid){ int p=0,len=0; for(int i=0;s[i];i++,len++){ int k=s[i]-'a',&x=next[p][k]; p=x?x:x=newnode(); } //初始化单词末尾节点的一些信息 ans[p]={0,0}; lasp[p]=-INF; lent[p]=len; //1代表查询0,2代表查询1,3代表两种查询 flag[p]|=(1<<type); //记录查询的种类和对应的位置 stp[sid]=type; sps[sid]=p; } int q[MAXL],front,rear; void makenext(){ q[front=rear=0]=0,rear++; while(front<rear){ int u=q[front++]; for(int i=0;i<26;i++){ int v=next[u][i]; if(v==0)next[u][i]=next[fail[u]][i]; else q[rear++]=v; if(v&&u)fail[v]=next[fail[u]][i]; } } } void makeans(char *s){ for(int i=0,p=0;s[i];i++){ int k=s[i]-'a'; p=next[p][k]; for(int f=p;f;f=fail[f]){ //对于可重叠覆盖的情况,直接统计 if(flag[f]&1){ ans[f][0]++; } //对于不可重叠覆盖的情况,选取后记录最后选取的位置 if(flag[f]&2){ if(lasp[f]+lent[f]<=i){ ans[f][1]++; lasp[f]=i; } } } } } int main(){ //freopen("test.in","r",stdin); int cas=1; while(scanf("%s",s)!=EOF){ scanf("%d",&n); pos=0;newnode(); for(int i=1;i<=n;i++){ scanf("%d%s",&type,s1); insert(s1,type,i); } makenext(); makeans(s); printf("Case %d\n",cas++); for(int i=1;i<=n;i++){ printf("%d\n",ans[sps[i]][stp[i]]); } printf("\n"); } }