萌新妹子简单KMP求助
查看原帖
萌新妹子简单KMP求助
227728
冰糖鸽子TJ鸽子协会楼主2021/8/16 18:43

RT,思路和题解一样,T的每行建AC自动机,S的每行Query一次。然后每列再KMP求一下出现次数。

这题题意就是问S这个大矩阵里,T这个小矩阵出现了多少次。

udebug\mathtt{udebug} 的数据过了,现在WA on 1kk

// Problem: UVA11019 Matrix Matcher
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA11019
// Memory Limit: 0 MB
// Time Limit: 3000 ms
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define M 1005
#define N 105
#define NM 1000
int fal[M],T,n,m,n2,m2,o=26,aft[M][M],at[N+M],fail[M],cnp,cntp,ans,rd[M*N][30],tag[M*N],ed[M];
string s[M],t[M],ft[M];
bool cmp(string a,string b) {return a<b;}
map<string,int>idd;
queue<int>q;
void Re()//多测清空
{
	memset(rd,0,sizeof(rd));
	memset(tag,0,sizeof(tag));
	idd.clear(),cntp=ans=cnp=0;
	memset(aft,0,sizeof(aft));
	memset(at,0,sizeof(at));
	memset(fail,0,sizeof(fail));
}
int tn(char cc) {return (cc-'a'+1);}//小写字母转数字
void Ins(string x,int id) //平凡的建字典树
{
	int now=0,len=x.length();
	for(int i=0;i<len;i++)
	{
		if(!rd[now][tn(x[i])]) rd[now][tn(x[i])]=++cntp;
		now=rd[now][tn(x[i])];
	}
	tag[now]=id,ed[id]=now; return;
}
void Dofail() //建Trie图/fail
{
	int u;
	for(int i=1;i<=o;i++) if(rd[0][i]) q.push(rd[0][i]);
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(int i=1;i<=o;i++)
		{
			if(rd[u][i]) fail[rd[u][i]]=rd[fail[u]][i],q.push(rd[u][i]);
			else rd[u][i]=rd[fail[u]][i];
		}
	}
	return;
}
void Query(string x,int id)
{
	int now=0,len=x.length();
	for(int i=0;i<len;i++)
	  now=rd[now][tn(x[i])],aft[id][i+1]=tag[now];
	return;
}
int Done() //KMP模板
{
	int j,res=0; fail[0]=0;
	for(int i=1;i<=n2+n;i++)
	{
		j=fail[i-1];
		while(j>0&&at[j]!=at[i]) j=fail[j-1];
		fail[i]=j+(at[i]==at[j]);
		res+=(fail[i]==n2?1:0);
	}
	return res;
}
int main()
{
	cin>>T;
	for(int i=1;i<=T;i++)
	{
		cin>>n>>m,Re(); for(int i=1;i<=n;i++) cin>>s[i];
		cin>>n2>>m2; for(int i=1;i<=n2;i++) cin>>t[i],ft[i]=t[i];
		sort(ft+1,ft+n2+1,cmp); //去重
		for(int i=1;i<=n2;i++) if(ft[i]!=ft[i-1]) Ins(ft[i],++cnp),idd[ft[i]]=cnp; Dofail(); //AC自动机
		for(int i=1;i<=n2;i++) at[i-1]=idd[t[i]]; //KMP的T
		for(int i=1;i<=n;i++) Query(s[i],i); //每行在自动机上跑一遍
		at[n2]=-1,ans=0;//-1是分隔符
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=n;j++) at[n2+j]=aft[j][i]; //弄出来要KMP的串
			ans+=Done();
		}
		cout<<ans<<endl;
	}
	return 0;
}
2021/8/16 18:43
加载中...