题目链接:
https://nanti.jisuanke.com/t/19970
思路:
KMP做这道题的想法
模板ABCA变成 -1 -1 -1 3
询问CBAABCA变成 -1 -1 -1 1 3 5 3(记作diff)
next数组是 0 1 2 3
匹配CBAABCA的时候,我记f[i]为匹配到第i个字符时候,模板串最长能匹配到哪,模板串匹配的最长位置为j
这样f就是 1 2 3 1 2 3 4
为什么f[4]变成了1,因为匹配到第四个的时候,要求s[4]==s[4-1],j一直跳到1,这时候diff[4]>=next,意味着这个diff[4]已经没用了,要变成-1
这样diff就变成了 -1 -1 -1 -1 3 5 3,此时j指向1
然后求f[5],发现5-3>=j,就把3变成-1,来匹配,因为让s[5]==s[2]已经没有用了,模板串长度不够,不需要考虑这个3
这样diff又变成了-1 -1 -1 -1 -1 5 3,此时next匹配上了,变成2
一直下去,求出所有的f
复杂度不会算,因为询问串每次都跳fail,不知道会覆盖多少个不同的状态,最坏情况是可能会是len^2?
#include<bits/stdc++.h> using namespace std; const int N=100005; int fail[N],cnt[N],deep[N]; map<int,int>ch[N]; int tot,root; int newnode(){ tot++; ch[tot].clear(); fail[tot]=0; cnt[tot]=0; return tot; } void init(){ for (int i=0;i<=tot;i++) ch[i].clear(); root=newnode(); } void insert(int *s,int n){ int now=root; int _deep=0; for (int i=1;i<=n;i++){ _deep++; int w=s[i]; assert(w<_deep); if (!ch[now].count(w)) ch[now][w]=newnode(); now=ch[now][w]; deep[now]=_deep; } cnt[now]++; } int getnext(int u,int w){ if (w>=deep[u]+1) w=-1; // for (auto &p:ch[u]){ // printf("ch %d:%d %d\n",u,p.first,p.second); // } // printf("%d %d %d \n",u,w,ch[u].count(w)); while(u!=root&&!ch[u].count(w)){ u=fail[u]; if (w>=deep[u]+1) w=-1; } if (ch[u].count(w)) return ch[u][w]; return u; } void build(){ queue<int>Q; fail[root]=root; for (auto &p:ch[root]){ int v=p.second; fail[v]=root; Q.push(v); } while(!Q.empty()){ int u=Q.front(); Q.pop(); for (auto &p:ch[u]){ int v=p.second; fail[v]=getnext(fail[u],p.first); Q.push(v); } } } int T; int vis[N]; bool query(int *s,int n){ int now=root; for (int i=1;i<=n;i++){ int w=s[i]; now=getnext(now,w); for (int v=now;v!=root&&vis[v]!=T;v=fail[v]){ vis[v]=T; if (cnt[v]) return 1; } } return 0; } char s[N*10]; int a[N*10]; int pre[26]; int main(){ int t; scanf("%d",&t); for (int cas=1;cas<=t;cas++){ init(); int n; scanf("%d",&n); for (int i=1;i<=n;i++){ memset(pre,0,sizeof(pre)); scanf("%s",s+1); int m=0; for (int j=1;s[j];j++){ int w=s[j]-'A'; if (pre[w]) a[j]=j-pre[w]; else a[j]=-1; pre[w]=j; m++; // printf("%d ",a[j]); } insert(a,m); } build(); // for (int i=1;i<=tot;i++) printf("%d %d %d\n",i,fail[i],deep[i]); scanf("%d",&n); printf("Case #%d: ",cas); for (int i=1;i<=n;i++){ T++; memset(pre,0,sizeof(pre)); scanf("%s",s+1); int m=0; for (int j=1;s[j];j++){ int w=s[j]-'A'; if (pre[w]) a[j]=j-pre[w]; else a[j]=-1; pre[w]=j; m++; } if (query(a,m)) printf("Y"); else printf("N"); if (i==n) printf("\n"); else printf(" "); } } }