洛谷P3502 [POI2010]CHO-Hamsters
? 解题记录 ? ? 洛谷 ? ? AC自动机 ? ? 矩阵快速幂 ? ? 最短路 ?    2018-06-27 22:01:21    563    0    0

题目描述

 

给出n个互不包含的字符串,要求你求出一个最短的字符串S,使得这n个字符串在S中总共至少出现m次,问S最短是多少

 

 (), 总字符不超过  。

 输入格式:

第一行两个整数n, m

接下来n行n个字符串

输出格式:

 一行表示最短长度。

 

输入输出样例

输入样例#1: 复制
4 5
monika
tomek
szymon
bernard
输出样例#1: 复制
23​
 ​

 

这题好想,就是处理每一个字符串AC自动机结尾到另一个结尾的最短路矩阵加速。

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<queue>
#define LL long long
using namespace std;
const int maxn = 1e5 + 5;
const int N = 2e2 + 5;
int n, m;
char s[maxn];

struct edge {
    int v, next, w;
}e[maxn << 2];
int head[maxn], cnt, key[maxn], bg[maxn];
void adde(const int &u, const int &v, const int &w) {
    e[++cnt] = (edge) {v, head[u], w};
    head[u] = cnt;
}
int len;
LL mat[N][N], pow[N][N], tmp[N][N];
namespace AC {
    int trie[maxn][26], cnt = 1, fa[maxn];
    int insert(char * s) {
        len = strlen(s);
        int now = 1, id;
        for(register int i = 0; i < len; ++i) {
            id = s[i] - 'a';
            if(trie[now][id]) now = trie[now][id];
            else now = trie[now][id] = ++cnt;
        }
        return now;
    }
    void create() {
        int v, u, p;
        queue<int > q;q.push(1);
        while(!q.empty()) {
            u = q.front();
            q.pop();
            for(register int i = 0; i < 26; ++i) {
                if(!trie[u][i]) continue;
                v = trie[u][i], p = fa[u];
                adde(u, v, 1);
                while(p && !trie[p][i]) p = fa[p];
                if(!p) fa[v] = 1;
                else fa[v] = trie[p][i];
                adde(v, fa[v], 0);
                q.push(v);
            }
        }
    }
}

int vis[maxn];LL dis[maxn];
void spfa(int st) {
    int in = 0;
    queue<int > q;
    memset(dis, 0x3f, sizeof(dis));
    q.push(key[st]), dis[key[st]] = 0;
    while(!q.empty()) {
        int u = q.front();
        q.pop(), vis[u] = 0;
        for(register int i = head[u]; i; i = e[i].next) {
            int v = e[i].v;
            if(dis[u] + e[i].w < dis[v]) {
                dis[v] = dis[u] + e[i].w;
                if(!vis[v]) vis[v] = 1, q.push(v);
            }
        }
        if(!in) dis[u] = 0x3f3f3f3f3f3f3f3f, in = 1;
    }
    for(register int i = 1; i <= n; ++i)
        mat[st][i] = dis[key[i]];
}

void mul(LL a[N][N], LL b[N][N]) {
    memset(tmp, 0x3f, sizeof(tmp));
    for(register int i = 1; i <= n; ++i)
        for(register int j = 1; j <= n; ++j)
            for(register int k = 1; k <= n; ++k)
                tmp[j][k] = min(a[j][i] + b[i][k], tmp[j][k]);
    memcpy(a, tmp, sizeof(tmp));
}

void fpow(LL a[N][N], int b) {
    while(b) {
        if(b & 1) mul(pow, a);
        b >>= 1, mul(a, a);
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for(register int i = 1; i <= n; ++i)
        scanf("%s", s), key[i] = AC::insert(s), bg[i] = len;
    AC::create();
    for(register int i = 1; i <= n; ++i) spfa(i);
    if(m > 1) {
        memcpy(pow, mat, sizeof(mat));
        fpow(mat, m - 2);
    }
    LL ans = 0x3f3f3f3f3f3f3f3f;
    for(register int i = 1; i <= n; ++i) 
        for(register int j = 1; j <= n; ++j)
            ans = min(ans, pow[i][j] + bg[i]);
    printf("%lld", ans);
    return 0;
}

 

上一篇: BZOJ 5093: [Lydsy1711月赛]图的价值

下一篇: HDU5739 Fantasia

563 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航