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
", res);

}


int main() {

    int _; scanf("%d", &_);
    while(_--) solve();

//    solve();

    return 0;
}

 

原文地址:https://www.cnblogs.com/Willems/p/13582123.html