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

【USACO 5.5.2】Hidden Password

时间:2016-03-27 12:19:07      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

题目大意

  给出从一个字符环,求从哪个位置断开后的字符串的字典序最小。

题解

  不多说,一条模板题。就是后缀数组(或后缀树)。

  先把字符串倍长,后缀数组预处理(请看相关资料),扫一遍SA数组,找符合条件的即可。

代码

/*
TASK:hidden
LANG:C++
*/

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 200005;

char s[MAXN];
int sa[MAXN], c[MAXN], x[MAXN], y[MAXN], n;

int main()
{
    freopen("hidden.in", "r", stdin);
    freopen("hidden.out", "w", stdout);
    scanf("%d\n", &n);
    for (int i = 0; i < n / 72 + 1; ++i)
    {
        for (int j = i * 72; j < i * 72 + 72 && j < n; ++j)
            scanf("%c", &s[j]);
        getchar();
    }
    for (int i = n; i < 2 * n - 1; ++i) s[i] = s[i % n];
    n = 2 * n - 1;
    memset(c, 0, sizeof(c));
    for (int i = 0; i < n; ++i) c[s[i]]++, x[i] = s[i];
    for (int i = 1; i < MAXN; ++i) c[i] += c[i - 1];
    for (int i = n - 1; i >= 0; --i) sa[--c[s[i]]] = i;
    int p;
    for (int k = 1; k <= n; k <<= 1)
    {
        p = 0;
        for (int i = n - k; i < n; ++i) y[p++] = i;
        for (int i = 0; i < n; ++i) if (sa[i] >= k) y[p++] = sa[i] - k;
        memset(c, 0, sizeof(c));
        for (int i = 0; i < n; ++i) c[x[y[i]]]++;
        for (int i = 1; i < MAXN; ++i) c[i] += c[i - 1];
        for (int i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1;
        x[sa[0]] = 0;
        for (int i = 1; i < n; ++i)
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++);
        if (p >= n) break;
    }
    if (p < n) printf("0\n");
    else
    {
        int ansloc = 0;
        while (sa[ansloc] >= (n + 1) / 2) ansloc++;
        printf("%d\n", sa[ansloc]);
    }
    return 0;
}

 

【USACO 5.5.2】Hidden Password

标签:

原文地址:http://www.cnblogs.com/albert7xie/p/5325152.html

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