test20181020 B君的第二题
B君的第二题
分析
题目就是让你求文本框与s匹配到了哪个位置。
考场70分
一看就是裸的kmp,直接打上去。
const int MAXN=1e5+8;
char s[MAXN],t[MAXN];
int n,m;
int nx[MAXN];
int f[MAXN],len;
int main()
{
freopen("xining.in","r",stdin);
freopen("xining.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
scanf("%s",t+1);
m=strlen(t+1);
for(int i=2;i<=n;++i)
{
int p=nx[i-1];
while(p&&s[p+1]!=s[i])
p=nx[p];
if(s[p+1]==s[i])
++p;
nx[i]=p;
}
printf("%d\n",n);
for(int i=1;i<=m;++i)
{
if(t[i]=='-')
{
--len;
if(len<0)
len=0;
printf("%d\n",n-f[len]);
continue;
}
// cerr<<"pro "<<i<<endl;
int p=f[len];
// cerr<<" p="<<p<<endl;
while(p&&s[p+1]!=t[i])
p=nx[p];
if(s[p+1]==t[i])
++p;
f[++len]=p;
// cerr<<" p="<<p<<endl;
printf("%d\n",n-p);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
结果TLE了。实际上时间复杂度\(O(n^2)\)
标解
这道题能卡kmp,是因为往回走后重新匹配跳next时复杂度没了保证。
退格操作可以让匹配长度剧增,这与kmp要满足长度增加量最多为文本串的长度的性质不符,所以要被卡。
B君:可以前n/2都是a,然后后面一个-一个b交替出现,就可以把kmp卡成n方的了。
但是AC自动机中的一个构建优化是把不存在的儿子补齐,所以考虑AC自动机。
然后因为AC自动机是在Trie图上建的,距离不能直接求,所以要预处理。
时间复杂度\(O(n)\)
const int MAXN=1e5+7;
vector<int>a[MAXN];
int d[MAXN];
const int CHARSET=26;
struct Trie
{
int sz;
int to[MAXN][CHARSET];
int nx[MAXN];
int fa[MAXN];
int v[MAXN];
il void ins(rg char*s)
{
rg int p=0;
for(;*s;++s)
{
rg int c=*s-'a';
if(to[p][c]==0)
{
to[p][c]=++sz;
fa[sz]=p;
}
p=to[p][c];
}
v[p]=1;
}
il void build()
{
rg queue<int>Q;
Q.push(0);
while(!Q.empty())
{
rg int x=Q.front();
Q.pop();
v[x]|=v[nx[x]];
for(rg int i=0;i<CHARSET;++i)
{
if(to[x][i])
{
nx[to[x][i]]=x?to[nx[x]][i]:0;
Q.push(to[x][i]);
}
else
{
to[x][i]=x?to[nx[x]][i]:0;
}
}
}
for(rg int i=0;i<=sz;++i)
for(rg int j=0;j<CHARSET;++j)
{
a[to[i][j]].push_back(i);
}
memset(d,0x3f,sizeof d);
for(rg int i=0;i<=sz;++i)
if(v[i])
{
Q.push(i);
d[i]=0;
}
while(!Q.empty())
{
rg int x=Q.front();
Q.pop();
for(rg int i=0;i<a[x].size();++i)
{
rg int y=a[x][i];
if(d[y]>d[x]+1)
{
d[y]=d[x]+1;
Q.push(y);
}
}
}
}
}T;
char s[MAXN],t[MAXN];
int f[MAXN],len;
int main()
{
freopen("xining.in","r",stdin);
freopen("xining.out","w",stdout);
scanf("%s",s);
T.ins(s);
T.build();
scanf("%s",t);
printf("%d\n",d[f[len]]);
for(rg int i=0;t[i];++i)
{
if(t[i]=='-')
{
if(len>0)
--len;
}
else
{
rg int x=T.to[f[len]][t[i]-'a']; // edit 1
f[++len]=x;
}
// cerr<<"f="<<f[len]<<endl;
printf("%d\n",d[f[len]]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
静渊以有谋,疏通而知事。