题目大意
S
是一个非空字符串,包含小写拉丁字母以及特殊字符
定义
求
T
的所有循环同构串(包括自己)中能与
循环同构串:将原串某前缀一道后面形成的串。在这里即使循环同构串看起来相同,但只要所选前缀不一样,就算做多个(即
T
有
1≤|T|≤100,1≤|S|≤100000
题目分析
我们将
T
串倍长以方便处理循环同构。
将
然后我们利用这个就可以模拟匹配过程了,注意开头结尾如果不是
∗
需要特殊处理。
还有就是细节很多,请读者自行思考。
时间复杂度
Codeforces上空间卡的紧,不能倍长
T
串,其实我们只用加长
代码实现
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;
const int M=100500;
const int N=105;
int part[N],len[N];
int n,m,ans,p,l;
char A[N],B[M];
int f[M][N];
bool match(int st,int en)
{
int cur=1,fn=p;
if (A[0]!='*'&&f[st][1]!=st) return false;
if (A[0]!='*') st+=len[1],cur++;
if (A[n-1]!='*'&&(en-len[p]+1<0||f[en-len[p]+1][p]!=en-len[p]+1)) return false;
if (A[n-1]!='*') en-=len[p],fn--;
if (st>en) return true;
for (int nxt;cur<=fn;st=nxt+len[cur],cur++)
{
nxt=f[st][cur];
if (nxt+len[cur]-1>en) return false;
}
return true;
}
int main()
{
freopen("journey.in","r",stdin),freopen("journey.out","w",stdout);
scanf("%s",A),n=strlen(A);
scanf("%s",B),l=m=strlen(B);
for (int i=m;i<m+n;i++) B[i]=B[i-m];
if (A[0]=='*')
{
if (A[1]!='*') part[p=1]=1;
}
else part[p=1]=0;
for (int i=1;i<n;i++)
if (A[i]=='*'&&i<n-1&&A[i+1]!='*')
part[++p]=i+1;
for (int i=1;i<=p;i++)
for (int j=part[i];j<n&&A[j]!='*';j++)
len[i]=j-part[i]+1;
m=m+n,ans=0,part[p+1]=n+1;
if (A[n-1]=='*') part[p+1]=n;
for (int i=1;i<=p;i++) f[m][i]=m;
for (int i=m-1;i>=0;i--)
{
for (int j=1;j<=p;j++)
{
bool AC=true;
for (int st=part[j];st<=part[j]+len[j]-1;st++)
if (A[st]!=B[i+st-part[j]])
{
AC=false;
break;
}
f[i][j]=AC?i:f[i+1][j];
}
}
for (int i=0;i<l;i++)
ans+=match(i,i+l-1);
printf("%d\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}