1. 程式人生 > >VOJ 字元加密Cipher (字尾陣列)

VOJ 字元加密Cipher (字尾陣列)

字元加密Cipher

題意

給你一個長度為N的字串,讓你輸出一個字串,要求,這個字串是原字串迴圈(即每次將第一個字元移至最後一個位置),總共會用N個這樣的字串,然後將這些字串按照字典序排列,按照順序每次輸出這些串的最後一個字元,這樣就形成了一個加密過的字串。

資料範圍: N<105N < 10^5

思路

首先,將所有字串排序,我們想到了什麼,字尾陣列啊。字尾陣列不是隻能對對於字尾的一些陣列進行排序嗎?而這裡是要求將所有迴圈字串進行排序,我們可以將原字串在後面複製一份,這樣可以保證所有後綴字串都比我們要求的字串要長。

這樣不會有什麼影響嗎?

我們可以驗證一下,如果字首都相等的話,我們才會需要比較後面一些的字元,而如果字首都相等了,後面的順序其實是無所謂的

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int MAXN = 2e5 + 10;
using namespace std;
char s[MAXN];

int N, M, rak[MAXN], sa[MAXN], tax[MAXN], tp[MAXN] ,a[MAXN];
void Debug() {
    printf("*****************\n");
    printf("下標"); for(int
i = 1; i <= N; i++) printf("%d ", i); printf("\n"); printf("sa "); for(int i = 1; i <= N; i++) printf("%d ", sa[i]); printf("\n"); printf("rak "); for(int i = 1; i <= N; i++) printf("%d ", rak[i]);printf("\n"); printf("tp "); for(int i = 1; i <= N; i++) printf("%d ", tp[
i]); printf("\n"); } inline void Qsort() { for(int i = 0; i <= M; i++) tax[i] = 0; for(int i = 1; i <= N; i++) tax[rak[i]]++; for(int i = 1; i <= M; i++) tax[i] += tax[i - 1]; for(int i = N; i >= 1; i--) sa[ tax[rak[tp[i]]]-- ] = tp[i]; } void SuffixSort() { M = 0;//可以看情況進行調節,我這裡進行了拉扯 for(int i = 1; i <= N; i++) rak[i] = a[i], tp[i] = i,M = max(M,a[i]); Qsort(); for(int w = 1, p = 0; p < N; M = p, w <<= 1) { p = 0; for(int i = 1; i <= w; i++) tp[++p] = N - w + i; for(int i = 1; i <= N; i++) if(sa[i] > w) tp[++p] = sa[i] - w;//這兩句是字尾陣列的核心部分,我已經畫圖說明 Qsort(); swap(tp, rak); rak[sa[1]] = p = 1; for(int i = 2; i <= N; i++) rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p; if (p > N) break; } } int main() { scanf("%s", s + 1); int len = strlen(s + 1); N = len*2; for (int i = 1;i <= len;i ++) s[i+len] = s[i]; for (int i = 1;i <= N;i ++) a[i] = s[i]-' '; SuffixSort(); for(int i = 1; i <= N; i++) if (sa[i] <= len) printf("%c", s[sa[i]+len-1]); }