• 【XSY3905】字符串题(lyndon串,构造)


    题面

    字符串题

    题解

    设所有长度不超过 (n) 的串的集合为 (S)

    考虑找到一种方法,能够对一个 lyndon 串 (A) ,直接求出 (A) 的下一个 lyndon 串。方法如下:

    1. 先将 (A) 不断复制, 取出前 (n) 位作为新的 (A) ,即 (Aleftarrow AAA⋯) 的前 (n) 位。
    2. 如果 (A) 的最后一位是 ('a'+m-1),即字符集中最大的字符,则将其删去,一直删除直到最后一位不为 ('a'+m-1)
    3. (A) 的最后一个字符变为这个字符在字符集中的后继。(其实 2、3 操作的实质是找到 1 操作后的 (A) 在字典序中的下一个字符串。

    设构造出的串为 (B)。证明这种方法的正确性,只需要证明 (B) 是 lyndon 串,且 (B)(S) 中字典序大于 (A) 的最小的 lyndon 串。

    • 先证 (B) 为 lyndon 串:

      根据构造方式,设 (A=a_1a_2⋯a_{|A|})。显然可以发现 (B)(AA⋯Aa_1a_2⋯a_x(a_{x+1}+1)) 的形式,其中 (1leq x<|A|)。由于 (A) 为 lyndon 串,所以对 (forall 1<i≤|A|),有 (a_ia_{i+1}cdots a_{|A|}a_1a_2⋯a_{i−1}>a_1a_2⋯a_{|A|})

      不难发现 (B) 的循环移位中 (B) 为其中的严格最小值,所以 (B) 为 lyndon 串。

    • 再证 (A,B) 之间没有 (lyndon) 串:

      如果有一个 (S) 中的串 (T) 字典序在 (A,B) 之间且为 lyndon 串,由构造方法可以知道 (A<T<AAA⋯)

      (T=AA⋯AT′),其中 (T') 的前 (|A|) 位不等于 AA ,显然有 (T'<A),则以 (T') 开头的循环移位小于 (T) ,与 (T) 是 lyndon 串矛盾。

    由于大部分满足条件的 lyndon 串的长度均为 (n),这个算法均摊复杂度为 (O(1)),可以 (O(x)) 通过此题。

    代码如下:

    #include<bits/stdc++.h>
     
    #define S 35
    #define N 200010
     
    using namespace std;
     
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=(x<<1)+(x<<3)+(ch^'0');
            ch=getchar();
        }
        return x*f;
    }
     
    struct Query
    {
        int x,id;
    }q[N];
     
    bool operator < (Query a,Query b)
    {
        return a.x<b.x;
    }
     
    int n,m,Q;
    int len;
    char s[S],Ans[N][S];
     
    int main()
    {
        n=read(),m=read(),Q=read();
        for(int i=1;i<=Q;i++)
            q[i].x=read(),q[i].id=i;
        sort(q+1,q+Q+1);
        len=1;
        s[0]='a';
        int tmp=1;
        while(tmp<=Q&&q[tmp].x==1)
        {
            for(int i=0;i<len;i++)
                Ans[q[tmp].id][i]=s[i];
            tmp++;
        }
        for(int i=2;i<=q[Q].x;i++)
        {
            int nowl=len;
            while(1)
            {
                for(int i=0;i<nowl&&len<n;i++)
                    s[len++]=s[i];
                if(len==n) break;
            }
            while(len>0&&s[len-1]=='a'+m-1) len--;
            s[len-1]++;
            while(tmp<=Q&&q[tmp].x==i)
            {
                for(int i=0;i<len;i++)
                    Ans[q[tmp].id][i]=s[i];
                tmp++;
            }
        }
        for(int i=1;i<=Q;i++)
        {
            for(int j=0;Ans[i][j];j++)
                putchar(Ans[i][j]);
            puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    用C语言编写生成小学四则运算程序
    每周学习报告
    读现代软件工程有感和自我介绍
    第七天
    第五天
    第六天
    作业九:课程总结
    作业四:结对编程项目--四则运算
    psp记录个人项目花费时间
    作业三:代码规范,代码复查
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14449409.html
Copyright © 2020-2023  润新知