zoukankan      html  css  js  c++  java
  • [ BZOJ 2882 ] 工艺

    (\)

    Description


    求一个串的所有循环同构串里字典序最小的一个。

    • (nle 3 imes 10^5)

    (\)

    Solution


    本来是找 SA 题找到这道的......

    首先 SA 的做法已经烂大街了,就是复制一遍求 (rank) ,取 (rank) 最高的长度 (ge n) 的后缀的前缀即可。

    后来突然想起来 (lyd) 的书上好像有个最小表示法是用来搞这个的,然后就去 % 了一发书.......

    最小表示法基于字典序的定义。

    首先将串复制一倍接在后面,显然它包含所有循环同构串。

    我们设当前比较的两个循环同构串,在大串里头指针分别是 (i,j)

    • 假如比到某一位置,发现 (s[i+k]<s[j+k])

      此时显然以 (j) 开始不是最优解。

      同时它带来了一系列的结论,即以 (j+1,j+2,...,j+k) 开始都不是最优解。

      因为我们总能从 (i+1,i+2,...,i+k) 的位置开始找出一个串使得字典序比它小。

      因此下一步 (j=j+k+1) ,因为比较两个相同的串没有意义,所以 (j+=(i==j))

    • 假如比到某一位置 (s[i+k]>s[j+k])

      此时讨论同上,令 (i=i+k+1,i+=(i==j)) 即可。

    当两个串比较长度 (=n) ,或某一头指针越过 (n) 了停止即可,答案就是那个还在 (n) 范围内的指针。

    (\)

    Code


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 600010
    #define R register
    #define gc getchar
    using namespace std;
     
    int s[N];
     
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
     
    int main(){
      int n=rd(),i,j,k;
      for(i=1;i<=n;++i) s[i]=s[n+i]=rd();
      for(i=1,j=2;i<=n&&j<=n;){
        for(k=0;k<=n&&s[i+k]==s[j+k];++k);
        if(k==n) break;
        if(s[i+k]>s[j+k]){i+=k+1;i+=(i==j);}
        else{j+=k+1;j+=(i==j);}
      }
      int ans=min(i,j);
      for(i=1;i<=n;++i) printf("%d ",s[i+ans-1]);
      return 0;
    }
    
  • 相关阅读:
    寒假短期学习计划
    PAT 1001 A+B 解题报告
    JavaScript 原型链、继承
    JavaScript 数据扁平化处理
    每周一篇React: 高阶 hoc_component 使用
    每天一道算法题: day1 翻转图像
    项目中下载加权,你是怎么做的,欢迎评论。
    前端封装验证码方法,封装验证码类
    文件下载之后默认不打开实现方式
    文件下载之后默认不打开实现方式
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9989225.html
Copyright © 2011-2022 走看看