1. 程式人生 > 實用技巧 >Minimum Index【】-2020杭電多校1

Minimum Index【】-2020杭電多校1

題目連結:

http://acm.hdu.edu.cn/showproblem.php?pid=6761

分析:

\(Lyndon\) 分解:
\(Lyndon\) 串:對於字串 \(s\),如果 \(s\) 的字典序嚴格小於 \(s\) 的所有後綴的字典序,我們稱 \(s\) 是簡單串,或者 \(Lyndon\) 串 。
性質:任意字串 \(s\) 都可以分解為 \(s=s_1s_2…s_k\),其中 \(∀s_i\)\(Lyndon\) 串且 \(s_i⩾s_{i+1}\),且這種分解方法是唯一的。

\(Duval\) 演算法:
該演算法可以在 \(O(n)\) 的時間內求出串 \(s\)

\(Lyndon\) 分解。
模板程式碼-Lyndon 分解

#include<bits/stdc++.h>
using namespace std;
const int MAXN = (1 << 21) + 1;
char s[MAXN];
int main() {
    scanf("%s", s + 1);
    int N = strlen(s + 1), j, k;
    for(int i = 1; i <= N;) {
        j = i; k = i + 1;
        while(k <= N && s[j] <= s[k]) {
            if(s[j] < s[k]) j = i;
            else j++;
            k++;
        }
        while(i <= j) {
            printf("%d ", i + k - j - 1);
            i += k - j;
        }
    }
    return 0;
}

程式碼:


#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=1e6+6;
const int mod=1e9+7;
int ans[N];
char ss[N];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",ss+1);
        int len=strlen(ss+1);
        int i=1;
        ans[1]=1;
        while(i<=len)
        {//重新開始分解
            int j=i,k=i+1;//i是近似串的開始
            while(k<=len&&ss[j]<=ss[k])
            {
                if(ss[j]<ss[k])//加入到近似的Lyndon串中
                {
                    j=i;
                    ans[k]=i;
                }
                else//繼續保持
                {
                    ans[k]=ans[j]+k-j;
                    j++;
                }
                k++;
            }
            while(i<=j)//起點向後移
                i+=k-j;
            ans[k]=i;//
        }
        ll base=1112,fac=1,res=0;
        for(int i=1;i<=len;i++)
        {
            res=(res+fac*ans[i]%mod)%mod;
            fac=fac*base%mod;
        }
        printf("%lld\n",res);
    }
    return 0;
}

參考部落格:
https://oi-wiki.org/string/lyndon/
https://www.cnblogs.com/zwfymqz/p/10198690.html
https://www.cnblogs.com/st1vdy/p/13362219.html