dis[i][j][k]表示从第i个串的结尾到第j个串的结尾走过2^k个串的最小长度
dis[i][j][0]=len[j]-cal(i,j)
cal(i,j)表示如果i的最长后缀等于j的最长前缀
倍增floyd好了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define inf 100000000000000000ll
#define maxn 210
using namespace std;
unsigned long long p1=233,p2=10007;
unsigned long long hash1[210][10010],hash2[210][10010],P1[10100],P2[10010];
long long f[40][maxn][maxn],g[maxn][maxn],g1[maxn][maxn];
char s[maxn][10100];
int len[maxn];
long long ans;
int m,n;
unsigned long long Hash1(int x,int l,int r)
{
return hash1[x][r]-hash1[x][l-1]*P1[r-l+1];
}
unsigned long long Hash2(int x,int l,int r)
{
return hash2[x][r]-hash2[x][l-1]*P2[r-l+1];
}
int cal(int x,int y)
{
for (int i=min(len[x],len[y])-1;i>=0;i--)
if (Hash1(x,len[x]-i+1,len[x])==Hash1(y,1,i) && Hash2(x,len[x]-i+1,len[x])==Hash2(y,1,i)) return i;
}
int Log(int x)
{
int ans=0;
while (x) x>>=1,ans++;
return ans;
}
int main()
{
//freopen("username.in","r",stdin);
//freopen("username.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
P1[0]=1;P2[0]=1;
for (int i=1;i<=1000;i++) P1[i]=P1[i-1]*p1,P2[i]=P2[i-1]*p2;
for (int i=1;i<=n;i++)
{
len[i]=strlen(s[i]+1);
hash1[i][0]=0;hash2[i][0]=0;
for (int j=1;j<=len[i];j++) hash1[i][j]=hash1[i][j-1]*p1+s[i][j]-'a',hash2[i][j]=hash2[i][j-1]*p2+s[i][j]-'a';
}
int cnt=Log(m);
for (int k=0;k<=cnt;k++)
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
f[k][i][j]=inf;
for (int i=1;i<=n;i++) f[0][0][i]=len[i],f[0][i][0]=inf;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
f[0][i][j]=len[j]-cal(i,j);
for (int k=1;k<=cnt;k++)
for (int p=0;p<=n;p++)
for (int i=0;i<=n;i++)
if (f[k-1][i][p]!=inf)
for (int j=0;j<=n;j++)
if (f[k-1][p][j]!=inf)
f[k][i][j]=min(f[k][i][j],f[k-1][i][p]+f[k-1][p][j]);
bool flag=0;
for (int k=0;k<=cnt;k++)
if (m&(1<<k))
{
if (flag)
{
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
g1[i][j]=inf;
for (int p=0;p<=n;p++)
for (int i=0;i<=n;i++)
if (g[i][p]!=inf)
for (int j=0;j<=n;j++)
if (f[k][p][j]!=inf)
g1[i][j]=min(g1[i][j],g[i][p]+f[k][p][j]);
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
g[i][j]=g1[i][j];
}
else
{
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++)
g[i][j]=f[k][i][j];
flag=1;
}
}
long long ans=inf;
for (int i=1;i<=n;i++) ans=min(ans,g[0][i]);
printf("%lld\n",ans);
return 0;
}