$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
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/8372677.html