题意
给你一个文本串,下面n个匹配串,问你这些p中有多少可以由s[i~j] + s[l~r]凭借而来,可以退化成一段(j = l);
思路
Z-box模板题,pos数组是灵魂
分别处理出来p+'#'+s(void getz()) P+'#'+S(void getZ())的z数组(大写是小写的反序),
pos[i]记录长度为i的前半截字段的最小右端边界 即在getz()中 pos[z[i] - len] = min(pos[z[i] - len],i + z[i] - 1 - len); 枚举取min后:for(int i = len - 1;i >= 1; i--) pos[i] = min(pos[i + 1] - 1,pos[i]);//[啊啊啊灵魂啊这样处理出来才是最小有边界]
好的,pos ok之后,getZ(),对于每一位在P上的(i >len),判断一次为后半截是否可以拼出——if(pos[len - z[i]] <= len + LEN - i - z[i] + 1);//pos[len - z[i]]是前半截的右边界 判断是否小于等于 当前子段作为后半截的左边界。
中间wa了好几发 原因是应该pos[0] = 0 我还一直等于inf且没更新pos[0] 给我整傻啦
ACcode
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int MaxN = 1e5 + 1115;
const int inf = 0x3f3f3f3f;
int n,cnt,len,LEN;
char s[MaxN],S[MaxN],p[MaxN],P[MaxN];
int pos[MaxN],z[MaxN];
void getz(){
int l = 0,r = 0;
z[0] = 0;
for(int i = 1;i <= LEN + len; i++){
if(i > r){
int n = 0;
while(p[n] == p[i + n]) n++;
if(n){
l = i;
r = i + n - 1;
}
z[i] = n;
}
else{
if(z[i - l] < r - i + 1) z[i] = z[i - l];
else{
int n = 1;
while(p[r - i + n] == p[r + n]) n++;
r = r + n - 1;
l = i;
z[i] = r - l + 1;
}
}
if(i > len) pos[z[i]] = min(pos[z[i]],i + z[i] - 1 - len);
//pos[i]记录长度为i的字段的最小位置 from 1
}
for(int i = len - 1;i >= 1; i--) pos[i] = min(pos[i + 1] - 1,pos[i]);
}
void getZ(){
int l = 0,r = 0;
z[0] = 0;
for(int i = 1;i <= LEN + len; i++){
if(i > r){
int n = 0;
while(P[n] == P[i + n]) n++;
if(n){
l = i;
r = i + n - 1;
}
z[i] = n;
}
else{
if(z[i - l] < r - i + 1) z[i] = z[i - l];
else{
int n = 1;
while(P[r - i + n] == P[r + n]) n++;
r = r + n - 1;
l = i;
z[i] = r - i + 1;
}
}
if(i > len){//i是倒数第i个
if(pos[len - z[i]] <= LEN + len - i - z[i] + 1){
//pos[len - z[i]]:前半段右边界min
cnt++;//存在多种拆分答案
break;
}
}
}
}
int main()
{
scanf("%s",s);
scanf("%d",&n);
LEN = strlen(s);
for(int i = 0;i < LEN; i++) S[i] = s[LEN - i - 1];
while(n--){
for(int i = 1;i < MaxN; i++) pos[i] = inf;
scanf("%s",p);
len = strlen(p);
if(len == 1) continue;
p[len] = '#';
for(int i = 0;i < LEN; i++) p[len + i + 1] = s[i];
getz();
for(int i = 0;i < len; i++) P[i] = p[len - i - 1];
P[len] = '#';
for(int i = 0;i < LEN; i++) P[len + i + 1] = S[i];
getZ();
}
printf("%d\n",cnt);
}