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;
    }
    
  • 相关阅读:
    边工作边刷题:70天一遍leetcode: day 3
    边工作边刷题:70天一遍leetcode: day 3
    边工作边刷题:70天一遍leetcode: day 4
    边工作边刷题:70天一遍leetcode: day 4
    边工作边刷题:70天一遍leetcode: day 4
    javascript和jquery 获取触发事件的元素
    javascript 柯里化
    惰性函数
    IE6和IE7的line-height和现代浏览器不一致的问题
    img图片之间有空隙的问题
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9989225.html
Copyright © 2011-2022 走看看