1. 程式人生 > 實用技巧 >HDU 6761 Minimum Index (字串--Lyndon分解)

HDU 6761 Minimum Index (字串--Lyndon分解)

題目:傳送門

題意

給你一個字串,求每個字首的最小字尾對應的起始位置。

總的字串長度 <= 2e7

思路

Lydon 分解: 參考部落格

Lyndon 串:對於字串x,如果x的字典序嚴格小於x的所有後綴的字典序,我們稱x是簡單串,或者Lyndon串。

近似Lyndon串:若x為Lyndon串,則xxxx為近似Lyndon串,x′為x的字首。

Lyndon分解:將一個串x分作x1x2..xk,每一個部分都是Lyndon串,且 xi >= xi+1

定理:

Lyndon串是迴圈同構中字典序最小的一個。
Lyndon分解唯一。
兩個Lyndon串a,ba<b,有

abLyndon串。

通過 Lyndon 分解 解此題: 參考部落格

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define UI unsigned int
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define
pb push_back #define make make_pair #define INF 0x3f3f3f3f #define inf LLONG_MAX #define PI acos(-1) #define fir first #define sec second #define lb(x) ((x) & (-(x))) #define dbg(x) cout<<#x<<" = "<<x<<endl; using namespace std; const int N = 1e6 + 5; const LL mod = 1e9 + 7
; int n; char a[N]; LL ans[N]; void solve() { scanf("%s", a); n = strlen(a); int i = 0, j, k; ans[0] = 1LL; while(i < n) { j = i + 1, k = i; while(j < n && a[k] <= a[j]) { if(a[k] == a[j]) { ans[j] = j + ans[k] - k; k++; } else { k = i; ans[j] = i + 1; } j++; } while(i <= k) { i += j - k; } if(i == j && i < n) ans[j] = i + 1; } LL res = 0LL; dep(i, 0, n - 1) { res = (res * 1112LL % mod + ans[i]) % mod; } printf("%lld\n", res); } int main() { int _; scanf("%d", &_); while(_--) solve(); // solve(); return 0; }