码迷,mamicode.com
首页 > 其他好文 > 详细

@poj - 1509@ Glass Beads

时间:2019-01-10 20:53:16      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:amp   using   inf   str   通过   输入   clone   桶排序   space   

目录


@description@

给定一个由小写字母构成的圆环形的字符串(即首字母和末字母是相连的)。
让你找到一个位置将这个圆环形的串断开成为一个序列形的串,使得这个字符串字典序最小。如果有多个,输出位置最靠前的那一个。

input
多组数据。第一行输入数据组数 N。
接下来 N 行,每行一个长度不超过 10000 个字符的字符串。保证仅由小写字母组成。

output
对于每组数据,输出一个位置。表示以这个位子作为字符串起点字符串的字典序最小。

sample input
4
helloworld
amandamanda
dontcallmebfu
aaabaaa
sample output
10
11
6
5

@solution@

据说这道题可以用什么……最小表示法来做。不过我觉得反正后缀自动机也不难写,就直接用后缀自动机吧。

圆环嘛,我们就把原字符串 S 后面再拼一个 S ,然后求 SS 长度为 |S| 且字典序最小的串嘛。
后缀自动机中每一个结点都可以表示若干子串。
那我从起始结点出发,每次总是沿着字典序最小的边走,走 |S| 步不就可以了嘛。

它还要求位置最靠前。后缀自动机里面跟位置有关的,就是 end-pos 嘛。那我就是 end-pos 集合里面最小的那个再减去字符串长度就可以了嘛。

跟求解子串出现次数一样,我们把每次通过增量法增加的结点视为有效结点,再通过桶排序向 fa 转移,转移时取最小值即可。

@accepted code@

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF = (1<<30);
const int MAXN = 10000;
struct sam{
    sam *fa, *ch[26]; int mx;
    sam *nxt; int mnps;
}pl[4*MAXN + 5], *bin[2*MAXN + 5], *tcnt, *root, *lst;
void init() {
    tcnt = root = lst = &pl[0];
    for(int i=0;i<26;i++)
        root->ch[i] = NULL;
    root->nxt = root->fa = NULL;
    root->mx = 0, root->mnps = INF;
}
sam *newnode(int x = INF) {
    tcnt++;
    for(int i=0;i<26;i++)
        tcnt->ch[i] = NULL;
    tcnt->nxt = tcnt->fa = NULL;
    tcnt->mx = 0, tcnt->mnps = x;
    return tcnt;
}
void add_bin(sam *x) {
    x->nxt = bin[x->mx];
    bin[x->mx] = x;
}
char s[MAXN + 5];
void clone(sam *x, sam *y) {
    for(int i=0;i<26;i++)
        x->ch[i] = y->ch[i];
    x->fa = y->fa;
}
void sam_extend(int pos, int x) {
    sam *cur = newnode(pos), *p = lst;
    cur->mx = lst->mx + 1; lst = cur;
    add_bin(cur);
    while( p && !p->ch[x] )
        p->ch[x] = cur, p = p->fa;
    if( !p )
        cur->fa = root;
    else {
        sam *q = p->ch[x];
        if( p->mx + 1 == q->mx )
            cur->fa = q;
        else {
            sam *nq = newnode();
            clone(nq, q);
            nq->mx = p->mx + 1;
            add_bin(nq);
            cur->fa = q->fa = nq;
            while( p && p->ch[x] == q )
                p->ch[x] = nq, p = p->fa;
        }
    }
}
void solve() {
    init(); scanf("%s", s);
    int lens = strlen(s);
    for(int i=0;i<lens;i++)
        sam_extend(i, s[i]-‘a‘);
    for(int i=0;i<lens;i++)
        sam_extend(lens+i, s[i]-‘a‘);
    for(int i=2*lens;i>=1;i--)
        while( bin[i] ) {
            bin[i]->fa->mnps = min(bin[i]->fa->mnps, bin[i]->mnps);
            bin[i] = bin[i]->nxt;
        }
    sam *nw = root;
    for(int i=0;i<lens;i++) {
        for(int j=0;j<26;j++)
            if( nw->ch[j] ) {
                nw = nw->ch[j];
                break;
            }
    }
    printf("%d\n", (nw->mnps + 1)%lens + 1);
}
int main() {
    int N; scanf("%d", &N);
    for(int i=1;i<=N;i++) solve();
}

@details@

注意因为字符串扩展成了两倍,所以数组要相应的开成两倍大。否则会 RE。

@poj - 1509@ Glass Beads

标签:amp   using   inf   str   通过   输入   clone   桶排序   space   

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/10252268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!