题解:其实就是在找最少需要多少原串中的子串构成询问串,SAM进行匹配就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int len[maxn * 2], //最长子串的长度(该节点字串数量=len[x]-len[link[x]])
link[maxn * 2], //后缀链接(最短串前部减少一个字符所到达的状态)
nex[maxn * 2][26], //状态转移(尾部加一个字符的下一个状态)(图)
idx, //节点编号
last; //最后节点
void Iint() {
last = idx = 1;
link[1] = len[1] = 0;
memset(nex,0,sizeof(nex));
}
void Extend(int c) {
int x = ++idx;
len[x] = len[last] + 1;
int p;
for (p = last; p && !nex[p][c]; p = link[p])nex[p][c] = x;
if (!p)link[x] = 1;
else {
int q = nex[p][c];
if (len[p] + 1 == len[q])
link[x] = q;
else {
int nq = ++idx;
len[nq] = len[p] + 1;
link[nq] = link[q];
memcpy(nex[nq], nex[q], sizeof(nex[q]));
for (; p&&nex[p][c] == q; p = link[p])
nex[p][c] = nq;
link[q] = link[x] = nq;
}
}
last = x;
}
char str[maxn];
int dp[maxn<<1];//记录询问串位置为i需要多少子串。
void solve(){
int lenx=strlen(str+1); int p=1,tmp=0;
for(int i=1;i<=lenx;i++){
int x=str[i]-'A';
if(nex[p][x]) p=nex[p][x],tmp++; //如果直接匹配长度加一。
else { //不匹配直接往上跳
while(!nex[p][x]&&p) p=link[p];
if(!p) p=1,tmp=0;
else {
tmp=len[p]+1;p=nex[p][x];
}
}
if(tmp==0) { //tmp为0表示在SAM中找不到
printf("-1\n");
return ;
}
dp[i]=dp[i-tmp]+1; //求得当前位置为i需要多少子串
}
printf("%d\n",dp[lenx]);
}
int main()
{
int n;
scanf("%s",str);
Iint();
for(int i=0;str[i];i++) Extend(str[i]-'A');
scanf("%d",&n);
while(n--){
scanf("%s",str+1);
solve();
}
return 0;
}