洛谷P1709 [USACO5.5]隱藏口令Hidden Password(最小表示法)
阿新 • • 發佈:2018-06-29
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後綴自動機85; 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; }
// 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(最小表示法)