数组开小毁一生……

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085

这题在洛谷上有个条件是“互不包含”,其实bzoj的数据也满足这个条件,否则我目前已知的所有做法都是错的。

个人觉得AC自动机可以用其他办法做,但是没试过

KMP(或者hash), \(f[i][j]\)表示\(i\)完了接上\(j\)需要多少个字符,直接用KMP求出最长的同时是\(j\)串的前缀和\(i\)串的后缀的串即可

然后求走\((m-1)\)步的最短路,倍增Floyd

并不是多串匹配一定要用AC自动机!即使不考虑正确性,AC自动机的Trie树在复杂度上可能还多个字符集大小,不一定比KMP快,一定要合理选择!

代码

KMP:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
using namespace std;

const int N = 200;
const int S = 26;
const int L = 1e5+1e3;
const int LGM = 30;
const llong INF = 1e17;
llong f[N+3][N+3],g[N+3][N+3],g0[N+3][N+3];
char a[L+3];
int nxt[L+3];
int len[L+3];
int slen[L+3];
int n; llong m;

void update(llong &x,llong y) {x = min(x,y);}

int KMP(char str1[],char str2[],int len1,int len2)
{
	for(int i=0; i<=len1; i++) nxt[i] = 0;
	for(int i=2; i<=len1; i++)
	{
		nxt[i] = nxt[i-1];
		while(nxt[i]!=0 && str1[i]!=str1[nxt[i]+1])
		{
			nxt[i] = nxt[nxt[i]];
		}
		if(str1[i]==str1[nxt[i]+1]) nxt[i]++;
	}
	if(str1==str2)
	{
		return len1-nxt[len1];
	}
	else
	{
		int j = 0;
		for(int i=1; i<=len2; i++)
		{
			while(j && str1[j+1]!=str2[i])
			{
				j = nxt[j];
			}
			if(j<len1 && str1[j+1]==str2[i]) j++;
		}
		return len1-j;
	}
}

int main()
{
	scanf("%d%lld",&n,&m);
	for(int i=1; i<=n; i++)
	{
		scanf("%s",a+slen[i-1]+1); len[i] = strlen(a+slen[i-1]+1); slen[i] = slen[i-1]+len[i]+1; a[slen[i]] = ' ';
	}
	for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
	for(int i=1; i<=n; i++) f[i][i] = len[i];
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			g0[j][i] = KMP(a+slen[i-1],a+slen[j-1],len[i],len[j]);
		}
	}
	/*
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			printf("g0: %d %d %lld\n",i,j,g0[i][j]);
		}
	}
	*/
	m--;
	while(m>0)
	{
		if(m&1)
		{
			for(int k=1; k<=n; k++)
			{
				for(int i=1; i<=n; i++)
				{
					for(int j=1; j<=n; j++)
					{
						update(g[i][j],f[i][k]+g0[k][j]);
					}
				}
			}
			for(int i=1; i<=n; i++)
			{
				for(int j=1; j<=n; j++)
				{
					f[i][j] = g[i][j];
					g[i][j] = INF;
				}
			}
		}
		for(int k=1; k<=n; k++)
		{
			for(int i=1; i<=n; i++)
			{
				for(int j=1; j<=n; j++)
				{
					update(g[i][j],g0[i][k]+g0[k][j]);
				}
			}
		}
		for(int i=1; i<=n; i++)
		{
			for(int j=1; j<=n; j++)
			{
				g0[i][j] = g[i][j];
				g[i][j] = INF;
			}
		}
		m>>=1;
	}
	llong ans = INF;
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			ans = min(ans,f[i][j]);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

AC自动机WA+TLE代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#define llong long long
using namespace std;

const int N = 200;
const int S = 26;
const int L = 1e5+1;
const int LGM = 30;
const llong INF = 1e17;
void update(llong &x,llong y) {x = min(x,y);}
llong g0[N+3][N+3],g[N+3][N+3],f[N+3][N+3];
int len[N+3];
int fail[L+3];
int son[L+3][S+3];
int idpos[N+3];
char a[L+3];
int id[L+3];
int que[L+3];
int dep[L+3];
int n,rtn,siz; llong m;

void insertstr(char str[],int sid)
{
	int u = rtn;
	for(int i=1; i<=len[sid]; i++)
	{
		if(son[u][str[i]])
		{
			u = son[u][str[i]];
		}
		else
		{
			siz++; son[u][str[i]] = siz;
			u = siz;
		}
	}
	id[u] = sid;
	idpos[sid] = u;
}

void add(int u,int v,llong w)
{
	update(g0[id[u]][id[v]],w);
}

void getfail()
{
	int head = 1,tail = 0;
	for(int i=1; i<=S; i++)
	{
		int v = son[rtn][i];
		if(v)
		{
			tail++; que[tail] = v;
			fail[v] = rtn;
		}
	}
	while(head<=tail)
	{
		int u = que[head]; head++;
		for(int i=1; i<=S; i++)
		{
			int v = son[u][i];
			if(v) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = v;}
			else {son[u][i] = son[fail[u]][i];}
		}
	}
}

void bfs(int s)
{
	printf("bfs(%d)\n",s);
	for(int i=1; i<=siz; i++) dep[i] = 0;
	int head = 1,tail = 1; que[1] = s;
	while(head<=tail)
	{
		int u = que[head]; head++;
		int v = fail[i];
		for(int i=1; i<=S; i++)
		{
			v = son[u][i];
			if(v && dep[v]==0)
			{
				dep[v] = dep[u]+1;
				add(s,v,dep[v]);
				tail++; que[tail] = v;
			}
		}
	}
}

int main()
{
	scanf("%d%lld",&n,&m); rtn = siz = 0;
	for(int i=1; i<=n; i++)
	{
		scanf("%s",a+1); len[i] = strlen(a+1);
		for(int j=1; j<=len[i]; j++) a[j] -= 96;
		insertstr(a,i);
	}
	getfail();
	for(int i=0; i<=siz; i++) printf("AC%d fail%d\n",i,fail[i]);
	for(int i=0; i<=siz; i++) {for(int j=1; j<=S; j++) {if(son[i][j]) {printf("son[%d][%c]=%d\n",i,j+96,son[i][j]);}}}
	for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
	for(int i=1; i<=n; i++) f[i][i] = 0ll;
	for(int i=1; i<=siz; i++)
	{
		if(id[i])
		{
			bfs(i);
		}
	}
	/*
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			printf("g0: %d %d %lld\n",i,j,g0[i][j]);
		}
	}
	*/
	m--;
	while(m>0)
	{
		if(m&1)
		{
			for(int k=1; k<=n; k++)
			{
				for(int i=1; i<=n; i++)
				{
					for(int j=1; j<=n; j++)
					{
						update(g[i][j],f[i][k]+g0[k][j]);
					}
				}
			}
			for(int i=1; i<=n; i++)
			{
				for(int j=1; j<=n; j++)
				{
					f[i][j] = g[i][j];
					g[i][j] = INF;
				}
			}
		}
		for(int k=1; k<=n; k++)
		{
			for(int i=1; i<=n; i++)
			{
				for(int j=1; j<=n; j++)
				{
					update(g[i][j],g0[i][k]+g0[k][j]);
				}
			}
		}
		for(int i=1; i<=n; i++)
		{
			for(int j=1; j<=n; j++)
			{
				g0[i][j] = g[i][j];
				g[i][j] = INF;
			}
		}
		m>>=1;
	}
	llong ans = INF;
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			ans = min(ans,len[i]+f[i][j]);
		}
	}
	printf("%lld\n",ans);
	return 0;
}
/*
4 11
aaaaaaa
aaaa
aaaaaa
aaaaaaaaaa
*/