前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >洛谷P1709 [USACO5.5]隐藏口令Hidden Password(最小表示法)

洛谷P1709 [USACO5.5]隐藏口令Hidden Password(最小表示法)

作者头像
attack
发布2018-07-04 12:35:28
3080
发布2018-07-04 12:35:28
举报
文章被收录于专栏:数据结构与算法

题目描述

有时候程序员有很奇怪的方法来隐藏他们的口令。Binny会选择一个字符串S(由N个小写字母组成,5<=N<=5,000,000),然后他把S顺时针绕成一个圈,每次取一个做开头字母并顺时针依次取字母而组成一个字符串。这样将得到一些字符串,他把它们排序后取出第一个字符串。把这个字符串的第一个字母在原字符串中的位置-1做为口令。

如字符串alabala,按操作的到7个字符串,排序后得:

aalabal

abalaal

alaalab

alabala

balaala

laalaba

labalaa

第一个字符串为aalabal,这个a在原字符串位置为7,7-1=6,则6为口令。

输入输出格式

输入格式:

第一行:一个数:N

第二行开始:字符串:S(每72个字符一个换行符)

输出格式:

一行,为得到的口令

输入输出样例

输入样例#1: 复制

代码语言:javascript
复制
7
anabana

输出样例#1: 复制

代码语言:javascript
复制
6

说明

题目满足:

30%的数据n<=10000

70%的数据n<=100000

100%的数据n<=5000000

时限 1s

题目翻译来自NOCOW。

USACO Training Section 5.5

//20170523新增数据四组

这次后缀自动机卡不过去了qwq。尼玛空间太小了。。

然后就只能用最小表示法的专用算法了。大致流程就是维护三个指针$i, j, k$,然后判断$s[i+k]$和$s[j+k]$这两个位置哪个小,贪心的选

代码语言:javascript
复制
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 5000001;
int N;
char s[MAXN];
int fa[MAXN], len[MAXN], ch[MAXN][26], tot = 1, last = 1, root = 1; 
void insert(int x) {
    int now = ++tot, pre = last; last = now; len[now] = len[pre] + 1;
    for(; pre && !ch[pre][x]; pre = fa[pre]) 
        ch[pre][x] = now;
    if(!pre) fa[now] = root;
    else {
        int q = ch[pre][x];
        if(len[q] == len[pre] + 1) fa[now] = q;
        else {
            int nows = ++tot; len[nows] = len[pre] + 1;
            memcpy(ch[nows], ch[q], sizeof(ch[q]));
            fa[nows] = fa[q]; fa[q] = fa[now] = nows;
            for(; pre && ch[pre][x] == q; pre = fa[pre]) ch[pre][x] = nows;
        }
    }
}
int main() {
#ifdef WIN32
    freopen("a.in", "r", stdin);
#endif
    scanf("%d\n", &N);
    for(int i = 1; i <= N; i++) {
        s[i] = getchar();
        if(i % 72 == 0) getchar(), getchar();
    }
    tot = last = root = 1;
    for(int i = 1; i <= N; i++) s[i + N] = s[i];
    N <<= 1;
    for(int i = 1; i <= N; i++) insert(s[i] - 'a');
    int now = root, tot = 0;
    for(; tot <= N / 2; tot++) {
        for(int i = 0; i <= 25; i++) 
            if(ch[now][i])
                {now = ch[now][i];  break;}    
    } 
    printf("%d\n", len[now] - N / 2 - 1);
    return 0;
}
代码语言:javascript
复制
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN = 5000001;
int N;
char s[MAXN]; 
int main() {
#ifdef WIN32
    freopen("a.in", "r", stdin);
#endif
    ios::sync_with_stdio(0);
    cin >> N;
    for(int i = 0; i < N; i++) cin >> s[i];
    int i = 0, j = 1, k = 0;
    while(i < N && j < N) {
        k = 0;
        while(s[(i + k) % N] == s[(j + k) % N] && k < N) k++;
        if(k == N) return !printf("%d", min(i, j));
        if(s[(i + k) % N] > s[(j + k) % N]) i = i + k + 1;
        else j = j + k + 1;
        if(i == j) j++;
    }
    printf("%d", min(i, j));
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-06-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
  • 输入输出格式
  • 输入输出样例
  • 说明
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档