• BZOJ2085


    题目

    Tz养了一群仓鼠,他们都有英文小写的名字,现在Tz想用一个字母序列来表示他们的名字,只要他们的名字是字母序列中的一个子串就算,出现多次可以重复计算。现在Tz想好了要出现多少个名字,请你求出最短的字母序列的长度是多少。
    (注:所有名字都不互相包含)

    题解

    两两单词连边,边权为两个单词重叠连接后增加的长度,可以用kmp来求。

    所以问题就可以转化成在这个图上走m-1条的最短路径,用倍增floyd。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
    #define FI freopen(".//data_generator//in.txt","r",stdin)
    #define FO freopen("res.txt","w",stdout)
    #define pb push_back
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 1e18
    
    const int N = 210;
    const double eps = 1e-5;
    ll dis[N][N];
    char s[N][30000];
    int nt[30000];
     
    struct Floyd { //*运算符相当于作一次最短路运算
        static const ll inf;
        ll dis[N][N];
        int n;
        Floyd(int n, bool v = 1) : n(n) { //v: 1:inf, 0:0
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++) {
                    dis[i][j] = v ? inf : 0;
                }
            }
        }
        Floyd operator *(const Floyd & rhs) {
            Floyd tmp(n);
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++) {
                    for(int k = 1; k <= n; k++) {
                        tmp.dis[i][j] = min(tmp.dis[i][j], rhs.dis[i][k] + dis[k][j]); 
                    }
                }
            }
            return tmp;
        }
        void print() {
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= n; j++) {
                    cout << dis[i][j] << " ";
                }
                cout << endl;
            }
        }
        Floyd walk(int b) {
            Floyd res(n, 0);
            Floyd a(*this);
            while(b) {
                if(b & 1) {
                    res = res * a; //矩阵相乘顺序不能交换
                }
                a = a * a;
                b = b >> 1;
            }
            return res;
        }
    };
    const ll Floyd::inf = 1e18;
    
    void getnext(int p) {
        int i = 0,j = -1;
        nt[i] = j;
        while(s[p][i]) {
            if(j == -1 || s[p][i] == s[p][j]) {
                i++, j++;
                nt[i] = j;
            } else {
                j = nt[j];
            }
        }
    }
    
    int getlen(int a, int b) {
        int i = 1, j = 0;
        while(s[a][i]) {
            if(j == -1 || s[a][i] == s[b][j]) {
                i++, j++;
                if(!s[b][j]) break;
            } else {
                j = nt[j];
            }
        }
        return strlen(s[b]) - j;
    }
    
    int main() {
        IOS;
        int n, m;
        cin >> n >> m;
        for(int i = 1; i <= n; i++) {
            cin >> s[i];
        }
        Floyd ans(n);
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                getnext(j);
                ans.dis[i][j] = getlen(i, j);
                
            }
        }
        ans = ans.walk(m - 1);
        ll tans = INF;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                tans = min(tans, ans.dis[i][j] + (ll)strlen(s[i]));
            }
        }
        cout << tans << endl;
    }
    
  • 相关阅读:
    Java基于数据源的数据库访问
    新手接触java
    完成了第一个java
    Mysql服务器相互作用的通讯协议包括TCP/IP,Socket,共享内存,命名管道
    SQL 根据IF判断,SET字段值
    MyBatis SQL 生成方法 增删改查
    JAVA 文件转字节数组转字符串
    Word内容修改,以及转PDF
    SpringBoot编辑代码时不重启服务
    java 图片转换工具
  • 原文地址:https://www.cnblogs.com/limil/p/13502065.html
Copyright © 2020-2023  润新知