1. 程式人生 > >洛谷P1709 [USACO5.5]隱藏口令Hidden Password(最小表示法)

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

else win32 換行 event 分享圖片 ios copy 得到 自動機

題目描述

有時候程序員有很奇怪的方法來隱藏他們的口令。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: 復制
7
anabana
輸出樣例#1: 復制
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]$這兩個位置哪個小,貪心的選

技術分享圖片
// 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; }
後綴自動機85
// 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;
}

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