[UVA 719] [SPOJ 48] Beads

洛谷传送门
SPOJ传送门
UVA传送门

题目描述

PDF

img

输入输出格式

####输入格式:

img

输出格式:

img

输入输出样例

输入样例#1:
4
helloworld
amandamanda
dontcallmebfu
aaabaaa
输出样例#1:
10
11
6
5

解题分析

求最小表示, 直接将原串两次插入后缀自动机即可。 因为可能开头相同的子串很多, 所以要跳到末尾得到其 l e n len len值后减去字符串长度再加 1 1 1即可。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define MX 40050
char dat[MX];
int cnt, l, cur, last;
int len[MX], par[MX], to[MX][26];
namespace SAM
{
    IN void insert(R int id)
    {
        R int now = last, tar;
        cur = ++cnt; len[cur] = len[last] + 1;
        for (; (~now) && !to[now][id]; now = par[now]) to[now][id] = cur;
        if(now < 0) return par[last = cur] = 0, void(); tar = to[now][id];
        if(len[tar] == len[now] + 1) return par[last = cur] = tar, void();
        int nw = ++cnt; len[nw] = len[now] + 1;
        par[nw] = par[tar], par[tar] = par[last = cur] = nw;
        std::memcpy(to[nw], to[tar], sizeof(to[nw]));
        for (; (~now) && to[now][id] == tar; now = par[now]) to[now][id] = nw;
    }
    IN void calc()
    {
        R int now = 0;
        for (R int i = 1; i <= l; ++i)
        {
            for (R int j = 0; j < 26; ++j)
            if(to[now][j])
            {
                now = to[now][j];
                break;
            }
        }
        printf("%d\n", len[now] - l + 1);
    }
}
int main(void)
{
    int T;
    scanf("%d", &T);
    W (T--)
    {
        scanf("%s", dat + 1); l = std::strlen(dat + 1);
        par[last = cnt = 0] = -1; std::memset(to, 0, sizeof(to));
        for (R int i = 1; i <= l; ++i) SAM::insert(dat[i] - 'a');
        for (R int i = 1; i <= l; ++i) SAM::insert(dat[i] - 'a');
        SAM::calc();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值