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;
    }
    
  • 相关阅读:
    SQL Server 深入解析索引存储(非聚集索引)
    class.forName的官方使用方法说明
    使用C++实现学生管理系统
    hdu5033 Building 单调队列
    leetCode 72.Edit Distance (编辑距离) 解题思路和方法
    IOS7 textkit 的相关
    nodejs即时聊天
    5种语言混合编程:C++、JS、python、Lisp、汇编
    java Semaphore信号亮-同意多个任务同一时候訪问这个资源--thinking in java21.7.6
    关于Android的.so文件所须要知道的
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9989225.html
Copyright © 2011-2022 走看看