POJ 3581 Sequence(字尾陣列)題解

2022-07-20 03:00:12 字數 1662 閱讀 1983

已知某字串\(str\)滿足\(str_1 > max\\),現要求把這個字串分成連續的三組,然後每組都翻轉,問字典序最小是什麼?

因為\(str_1 > max\\),所以第一部分直接翻轉後跑\(sa\)求字典序最小就行了。那麼現在問題轉化為:把這個字串分成兩半,然後每組都翻轉,問字典序最小是什麼?

我們假設這個字串為\(s_1s_2 \cdots s_n\),那麼可以得到分成兩半反轉後為\(s_ks_s_ \cdots s_1s_ns_ \cdots s_\),我們可以發現,這個串其實就是\(s_ns_s_ \cdots s_1s_ns_ \cdots s_\)的乙個子串,那麼我就把這個串反向複製兩遍,然後字尾陣列求字典序最小即可。

tips:多組輸入必wa

#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

typedef unsigned long long ull;

const int maxn = 4e5 + 10;

const int inf = 0x3f3f3f3f;

const ull seed = 11;

const int mod = 1e9 + 7;

using namespace std;

int str[maxn];

int t1[maxn], t2[maxn], c[maxn];

int sa[maxn];

int rk[maxn];

int height[maxn];

bool cmp(int *r, int a, int b, int l)

void da(int *str, int n, int m)

// int k = 0;

// n--;

// for(i = 0; i <= n; i++) rk[sa[i]] = i;

// for(i = 0; i < n; i++)

}vectorvv;

int s[maxn];

int ans[maxn];

int main()

max = vv.size() + 2;

//1int len = n - 2;

int cnt = 0;

for(int i = len, j = 0; i >= 1; i--, j++)

str[len] = 0;

da(str, len, max);

for(int i = sa[1]; i < len; i++)

//2len = 0;

for(int i = n; i > cnt; i--)

for(int i = n; i > cnt; i--)

str[len] = 0;

da(str, len, max);

int st;

for(int i = 1; ; i++)

}for(int i = st; cnt < n; i++)

for(int i = 0; i < cnt; i++)

return 0;

}

POJ3581 Sequence 字尾陣列)

大致題意 給出n個數,把這個數列分為三段,再把三段反轉後連線在一起成為乙個新串,求字典序最小的新串。大致思路 由於需要翻轉,所以在輸入時就按照反序輸入。比如樣例輸入是5 10 1 2 3 4。我們從後向前讀入就變為5 4 3 2 1 10。對這列數求出字尾陣列。在大於2的後最中找到最小的字尾並輸出。...

POJ3581 Sequence(字尾陣列)

題意 給乙個串,串的第乙個字元比後面的都大,要把它分成三段,然後反轉每一段,求能得到的字典序最小的串是什麼。首先,第一段是可以確定的 把原串反轉,因為第乙個字元是最大的,它是唯一的,不存在反轉串的字尾之間有包含關係,所以取最小的字尾這就是第一段的字串 然後後面兩段,如果確定分割位置可以發現這兩段字串...

字尾陣列 poj3581 Sequence

考慮第一次切割,必然切割的是翻轉後字典序最小的字首,偽證 若切割位置更靠前 則會導致第乙個數翻轉後更靠前,字典序必然更大。若切割位置更靠後,則顯然也會導致字典序更大。sa即可 對於第二次切割,有結論 將序列分割成兩段再分別翻轉得到的序列,可以看作是將兩個原序列拼接得到的新序列中的某個字串翻轉得到的序...