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; }