[后缀自动机] HDU5558 Alice's Classified Message

本文介绍了一种基于字符串的加密算法——Alice密文算法,并详细解释了其实现过程。通过构造特殊的自动机(SAM),算法能够高效地找到字符串中的重复模式,并将其转化为密文形式输出。文中提供了一个C++实现的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Alice’s Classified Message

题意:

给一个串s,给一个加密过程,输出密文,过程如下:
初始i = 0,重复下面直到串结束。
找一个子串,第一个字符位于[0,i),而且该子串要和以i开头的相同长度的串相等,多个合法的取最长的,如果还有多个取最左边的,设该字串长度为k。
如果不存在,输出 -1和s[i]的ascii值,i增加1。
否则输出长度k和第一个字符的位置T,i增加k。

显然i=0时一定输出-1和s[0]。

思路:

比较裸,利用SAM的联机特性,一边找一边建,还要求最小的下标就多维护一个first_endpos。

//
//  main.cpp
//  1007
//
//  Created by 翅膀 on 16/9/11.
//  Copyright © 2016年 kg20006. All rights reserved.
//

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int N = 2e5+550;
struct SAM{
    int pre[N], son[N][26], maxlen[N], fend[N];
    int cur, root, last;
    int newnode(){
        pre[++cur] = 0, maxlen[cur] = fend[cur] = 0;
        memset(son[cur], 0, sizeof(son[cur]));
        return cur;
    }
    void init(){
        cur = 0;
        root = last = newnode();
    }
    void insertc(int w, int i){
        int p = last;
        int np = newnode(); fend[np] = i;
        maxlen[np] = maxlen[p]+1;
        while(p != 0 && son[p][w] == 0) son[p][w] = np, p = pre[p];
        if(p == 0) pre[np] = root;
        else{
            int q = son[p][w];
            if(maxlen[q] == maxlen[p]+1) pre[np] = q;
            else{
                int nq = newnode(); fend[nq] = fend[q];
                memcpy(son[nq], son[q], sizeof(son[q]));
                maxlen[nq] = maxlen[p]+1;
                pre[nq] = pre[q];
                pre[q] = nq;
                pre[np] = nq;
                while(p != 0 && son[p][w] == q) son[p][w] = nq, p = pre[p];
            }
        }
        last = np;
    }
    int nex(int p, int c){
        return son[p][c];
    }
}sam;
char s[N];
int main(int argc, const char * argv[]) {
    int T, ca = 1;
    scanf("%d", &T);
    while(T--){
        sam.init();
        scanf("%s", s);
        int len = (int)strlen(s);
        printf("Case #%d:\n", ca++);
        for(int i = 0; i < len; ){
            int p = sam.root, k = 0;
            while(i < len && sam.nex(p, s[i]-'a')){
                p = sam.nex(p, s[i]-'a');
                sam.insertc(s[i]-'a', i);
                ++k, ++i;
            }
            if(k) printf("%d %d\n", k, sam.fend[p]-k+1);
            else {
                sam.insertc(s[i]-'a', i);
                printf("-1 %d\n", (int)s[i]);
                ++i;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值