题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1960
题意:给出一个n*m的字母矩阵T和一个x*y的字母矩阵S。求S在T中出现了多少次?
思路:将S的每行看做一个串插入ac自动机。用T的每一行去匹配。那么我们可以得到每一次匹配都匹配了S的哪些行的串以及在T的这一行的哪个位置匹配到这个S的串。我们用f[i][j]表示以(i,j)为左上角的T,匹配了S的多少行。设某一次T的第r行匹配了S的第i行,位置是[c,c+y-1],那么令f[r-i][c]++。最后f[i][j]=x的就是能够完整匹配S的位置。
struct node
{
int c[26];
int fail;
int a[105],aNum;
void init()
{
clr(c,0); fail=-1;
aNum=0;
}
};
node a[N];
int cnt;
void insert(char *s,int id)
{
int i,x,p=0;
for(i=0;s[i];i++)
{
x=s[i]-'a';
if(!a[p].c[x])
{
a[p].c[x]=++cnt;
a[cnt].init();
}
p=a[p].c[x];
}
x=++a[p].aNum;
a[p].a[x]=id;
}
void build()
{
queue<int> Q;
int i,u,p,q;
Q.push(0);
while(!Q.empty())
{
u=Q.front();
Q.pop();
FOR0(i,26)
{
if(a[u].c[i]!=0)
{
p=a[u].c[i];
q=a[u].fail;
if(q!=-1) a[p].fail=a[q].c[i];
else a[p].fail=0;
Q.push(p);
}
else
{
q=a[u].fail;
if(q!=-1) a[u].c[i]=a[q].c[i];
else a[u].c[i]=0;
}
}
}
}
int f[1005][1005];
int n,m,X,Y;
char T[1005][1005],S[105][105];
void match(char *s,int r)
{
int p=0,i,x,c,j,k;
for(i=0;s[i];i++)
{
x=s[i]-'a';
p=a[p].c[x];
if(a[p].aNum)
{
c=i-Y+1;
FOR1(k,a[p].aNum) if(r>=a[p].a[k])
{
f[r-a[p].a[k]][c]++;
}
}
j=a[p].fail;
while(j>0)
{
if(a[j].aNum)
{
c=i-Y+1;
FOR1(k,a[j].aNum) if(r>=a[j].a[k])
{
f[r-a[j].a[k]][c]++;
}
}
j=a[j].fail;
}
}
}
int main()
{
rush()
{
a[0].init(); cnt=0;
int i,j;
RD(n,m);
FOR0(i,n) RD(T[i]);
RD(X,Y);
FOR0(i,X) RD(S[i]),insert(S[i],i);
build(); clr(f,0);
FOR0(i,n) match(T[i],i);
int ans=0;
FOR0(i,n) FOR0(j,m) if(f[i][j]>=X) ans++;
PR(ans);
}
}