HDU 3374 最小 / 大表示法

题意

传送门 HDU 3374 String Problem

题解

求字符串中字典序最小与最大的循环同构串,并求解对应的起始字符在原字符串中出现的位置最早的一个,以及这个循环同构串出现的次数。

最小/大表示法

字符串字典序最小/大的循环同构串称为字符串的最小/大表示。设字符串 S S S 长度为 n n n,最小/大表示法的可以 O ( n ) O(n) O(n) 求解,区别只在于字典序的判断。以最小表示法的求解为例,将原串 S S S 复制一份接在其结尾,得到的字符串记为 S S SS SS,则有 S S [ i , i + n ) , i ∈ [ 0 , n ) SS[i, i+n),i\in[0, n) SS[i,i+n),i[0,n) S S S 的以 i i i 为起始位的循环同构串。

对于任意的 i , j i,j i,j,观察其字典序比较过程, 设 k ( k < n ) k(k<n) k(k<n) 为以 i , j i,j i,j 为起始位置的循环同构串的最长前缀匹配长度,若 S S [ i + k ] > S S [ j + k ] SS[i+k]>SS[j+k] SS[i+k]>SS[j+k],那么对于以位置 [ i , i + k ] [i,i+k] [i,i+k] 为起始位置的循环同构串,都存在对应的起始位置 [ j , j + k ] [j,j+k] [j,j+k] 的字典序更小的循环同构串,跳过这些位置,一定不会遗漏最小表示的起始位置。于是初始化 i = 0 , j = 1 i=0,j=1 i=0,j=1,不断比较以 i , j i,j i,j 为起始位置的循环同构串,若 k < n k<n k<n,则按照上述规则不断跳过不可能为备选答案的位置,最终当 i ≤ n i\leq n in j ≤ n j\leq n jn 时,所有循环同构串都进行过比较,那么 m i n ( i , j ) min(i,j) min(i,j) 即最小表示的起始位置;若出现 k = n k=n k=n 的情况,说明 S S S 有更小的循环元,由于 i , j i,j i,j 从左向右扫描,则 i , j i,j i,j 分别为最小表示的最小起始位置和次小起始位置,则 m a x ( i , j ) − m i n ( i , j ) max(i,j)-min(i,j) max(i,j)min(i,j) 为最小循环元的长度。

那么,若求解最小表示法时出现 k = n k=n k=n,那么 m i n ( i , j ) min(i,j) min(i,j) 为最小表示对应的起始字符在原字符串中出现的位置最早的一个,出现次数为 n / [ m a x ( i , j ) − m i n ( i , j ) ] n/[max(i,j)-min(i,j)] n/[max(i,j)min(i,j)];反之, S S S 不存在更小的循环元, m i n ( i , j ) min(i,j) min(i,j) 为最小表示对应的起始字符在原字符串中出现的位置最早的一个,出现次数为 1 1 1

循环元存在性证明

方便起见,设字符串长度为 x x x,设 i , j i,j i,j 从左向右扫描出现的最早满足 k = x k=x k=x 情况的下标分别为 0 0 0 y , y ∈ [ 1 , x ) y,y\in[1,x) y,y[1,x),对应的循环同构串为 A , B A,B A,B

先证必要性。若 S S S 存在长度小于 x x x 的循环元,设其长度为 y y y,那么以 k t , t ∈ [ 0 , x / y ) kt,t\in [0,x/y) kt,t[0,x/y) 为起始位置的循环同构串相等,则比较字典序时出现 k = x k=x k=x 情况。

再证充分性,若 y ∣ x y\mid x yx,此时
A [ n − y , n ) = B [ n − 2 y , n − y ) = A [ n − 2 y , n − y ) A[n-y,n)=B[n-2y,n-y)=A[n-2y,n-y) A[ny,n)=B[n2y,ny)=A[n2y,ny) 递推到边界,可以观察到 A , B A, B A,B 是按照循环节的长度交错排列的,且存在长度为 y y y 的循环节;若 y ∤ x y\nmid x yx,按照上述思路递推,在边界上有
A [ 0 , y ) = S [ 0 , y ) = B [ n − y , n ) = B [ x % y , x % y + y ) = A [ x % y , x % y + y ) A[0,y)=S[0,y)=B[n-y,n)=B[x\% y,x\%y+y)=A[x\%y,x\%y+y) A[0,y)=S[0,y)=B[ny,n)=B[x%y,x%y+y)=A[x%y,x%y+y) x ′ = y , y ′ = x % y x'=y,y'=x\%y x=y,y=x%y,则得到规模缩小的原问题。设 f ( x , y ) f(x,y) f(x,y) 代表字符串长度为 x x x 2 2 2 个循环同构串起始位置索引差值为 y y y 且相等时原串 S S S 是否存在长度小于 x x x 的循环节,那么有
f ( x , y ) = f ( y , x % y ) f(x,y)=f(y,x\%y) f(x,y)=f(y,x%y) 递归问题的形式与欧几里德算法一致,边界情况 f ( g c d ( x , y ) , 0 ) f(gcd(x,y),0) f(gcd(x,y),0) 不满足 y ∈ [ 1 , x ) y\in[1,x) y[1,x),但可以推出递归的前一步为真,以其为递归的终点,则可以判断 f ( x , y ) f(x,y) f(x,y) 为真,且循环节长度为 g c d ( x , y ) gcd(x,y) gcd(x,y)

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000005;
char S[maxn * 2];
int n, rnk, t;

void solve(bool f)
{
    int i = 0, j = 1, k;
    while (i < n && j < n)
    {
        for (k = 0; k < n && S[i + k] == S[j + k]; ++k)
            ;
        if (k == n)
        {
            rnk = min(i, j), t = n / (max(i, j) - rnk);
            return;
        }
        bool g = (!f && S[i + k] > S[j + k]) || (f && S[i + k] < S[j + k]);
        if (g)
            i += k + 1, i += i == j;
        else
            j += k + 1, j += i == j;
    }
    rnk = min(i, j), t = 1;
}

int main()
{
    while (~scanf(" %s", S))
    {
        n = strlen(S);
        memcpy(S + n, S, sizeof(char) * n);
        solve(0);
        printf("%d %d ", rnk + 1, t);
        solve(1);
        printf("%d %d\n", rnk + 1, t);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值