• hdu5558


    hdu5558

    题意

    给出一个字符串,按照特殊规则进行加密。
    假设已经加密了前 (i) 个字符,从第 (i+1) 个字符开始找到 (S[i..N]) 的长度为 (K) 的最长前缀等于 (S[T...T+K-1]) ,其中 (T < i)。要求 (K) 尽可能大, (T) 尽可能小。如果找不到输出 (-1) 以及当前字符的 (ASCII) 值,否则输出 (K T) ,然后 (i = i + K) 继续加密。

    分析

    按照题意去模拟,关键在于怎么快速找出前面出现过的子串。
    我们每次可能要插入一个或多个字符,后缀自动机可以很方便的找出前面出现过的子串(直接在后缀自动机上跑就行了)。
    后缀自动机能识别所有已经插入的字符串的子串。
    题目要求 (T) 最小,在插入所有字符后,我们可以预处理出每个状态下子串的最小的右端点下标。

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e5 + 10;
    int ch[MAXN << 1][26];
    int fa[MAXN << 1]; // 前继结点,如果当前结点可以接受某个后缀那么它的前继结点也可以接受
    int len[MAXN << 1]; // 从根结点到该结点的最大距离,这个状态(结点)代表的串长度区间 (len[fa], len]
    int cnt, last;
    void init() {
        memset(ch, 0, sizeof ch);
        memset(fa, 0, sizeof fa);
        last = cnt = 1; // root节点为 1 ,所以添加的字符从 2 开始
    }
    vector<int> nd;
    void clear() {
        for(int i = 0; i <= cnt; i++) {
            memset(ch[i], 0, sizeof ch[i]);
            fa[i] = len[i] = 0;
        }
        last = cnt = 1;
    }
    void add(int c) {
        int p = last, np = last = ++cnt;
        nd.push_back(np);
        len[np] = len[p] + 1;
        while(!ch[p][c] && p) {
            ch[p][c] = np;
            p = fa[p];
        }
        if(p == 0) fa[np] = 1;
        else {
            int q = ch[p][c];
            if(len[p] + 1 == len[q]) {
                fa[np] = q;
            } else {
                int nq = ++cnt;
                len[nq] = len[p] + 1;
                memcpy(ch[nq], ch[q], sizeof ch[q]);
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;
                while(ch[p][c] == q && p) {
                    ch[p][c] = nq;
                    p = fa[p];
                }
            }
        }
    }
    char S[MAXN];
    int al[MAXN], ar[MAXN];
    int st[MAXN << 1];
    int main() {
        int T, kase = 1;
        last = 1; cnt = 1;
        scanf("%d", &T);
        while(T--) {
            nd.clear();
            scanf("%s", S);
            int Len = strlen(S);
            int ct = 0;
            add(S[0] - 'a');
            al[ct] = -1; ar[ct++] = S[0];
            for(int i = 1; i < Len; ) {
                int c = S[i] - 'a';
                int now = 1, l = 0;
                while(ch[now][c] && i + l < Len) {
                    now = ch[now][c];
                    add(c);
                    l++;
                    c = S[i + l] - 'a';
                }
                if(l) {
                    al[ct] = l; ar[ct++] = now;
                } else {
                    al[ct] = -1; ar[ct++] = S[i];
                    add(S[i] - 'a');
                }
                i += l;
                if(!l) i++;
            }
            for(int i = 0; i < nd.size(); i++) {
                int tmp = nd[i];
                while(tmp != 1) {
                    if(!st[tmp]) {
                        st[tmp] = len[nd[i]];
                    } else break;
                    tmp = fa[tmp];
                }
            }
            printf("Case #%d:
    ", kase++);
            for(int i = 0; i < ct; i++) {
                if(al[i] == -1) printf("-1 %d
    ", ar[i]);
                else printf("%d %d
    ", al[i], st[ar[i]] - al[i]);
            }
            for(int i = 0; i <= cnt; i++) st[i] = 0;
            clear();
        }
        return 0;
    }
    
  • 相关阅读:
    (转)Maven实战(三)Eclipse构建Maven项目
    刷欢乐豆的方法
    R-pie()
    R-plot()
    10只老鼠与1000瓶药水
    资源共享
    第一只python小爬虫
    正则表达式之python实现
    马踏棋盘之贪心算法优化
    八皇后之回溯法解决
  • 原文地址:https://www.cnblogs.com/ftae/p/7624247.html
Copyright © 2020-2023  润新知