$bzoj2085$
$hash+倍增floyd$
$hash预处理出两个串中一个串最少需要加多少字符变成另一个$
$然后把名字看成点,距离看成边,相当于计算走k步的最短距离$
$套用倍增floyd解决$
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 205, M = 1e5 + 5, P = 2333; int n, m; struct matrix { ll a[N][N]; matrix() { memset(a, 0x3f3f3f, sizeof(a)); } matrix friend operator * (const matrix &a, const matrix &b) { matrix ret; for(int k = 0; k <= n; ++k) { for(int i = 0; i <= n; ++i) { for(int j = 0; j <= n; ++j) { ret.a[i][j] = min(ret.a[i][j], a.a[i][k] + b.a[k][j]); } } } return ret; } } a, b; int len[N]; ll h[N][M], pw[M]; char s[M]; ll cut(ll *h, int l, int r) { return h[r] - h[l - 1] * pw[r - l + 1]; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { scanf("%s", s + 1); len[i] = strlen(s + 1); for(int j = 1; j <= len[i]; ++j) { h[i][j] = h[i][j - 1] * P + s[j]; } } pw[0] = 1; for(int i = 1; i < M; ++i) { pw[i] = pw[i - 1] * P; } for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) { for(int k = min(len[i], len[j]) - 1; k >= 0; --k) { if(cut(h[i], len[i] - k + 1, len[i]) == cut(h[j], 1, k)) { b.a[i][j] = a.a[i][j] = len[j] - k; break; } } } } for(int i = 1; i <= n; ++i) { a.a[0][i] = b.a[0][i] = len[i]; } for(--m; m; m >>= 1, a = a * a) { if(m & 1) { b = b * a; } } ll ans = 1e18; for(int i = 1; i <= n; ++i) { ans = min(ans, b.a[0][i]); } printf("%lld\n", ans); return 0; }