队列变换 bzoj-1692 Usaco-2007 Dec

题目大意:给定一个长度为$n$的字符串。每次从头或尾取出一个字符加到另一个字符串里。要求变换后生成的字符串字典序最小,求字典序最小的字符串。

注释:$1\le n\le 3\cdot 10^4$。


想法

考虑暴力怎么做:

每次把当前字符串左右较小的取出来。如果一样就对着往中间枚举,直到不一样为止。

这样时间复杂度为$O(n^2)$,全是一样的字符即可卡掉。

显然上述过程我们就是比较正反两个字符串谁的字典序更小对吧。

那么我们把原串翻转然后接在原串后面。两个串中间加一个非字符集字符。

对这个新串建立后缀数组然后弄在这个新串上弄两个指针。

只需要比较这两个指针对应后缀谁在$sa$中更靠前即可,因为中间有一个不可见字符隔着所以互相不会影响。

如果是前面的指针较大那就把前面的指针向后移动,反之把后面的指针向前移动。输出刚才指向的字符即可。

由于后缀数组可以将后缀排序所以只要理解了上面的暴力那么正解的正确性显然。

Code

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define N 60010
  6. using namespace std;
  7. int Ws[N],wn[N],wa[N],wb[N],n,m=28,rk[N],ht[N],r[N<<1],sa[N],wv[N],x[N],y[N];
  8. inline char nc() {static char buf[100000],*p1,*p2;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
  9. inline int rd() {int x=0; char c=nc(); while(c<'0'||c>'9') c=nc(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=nc(); return x;}
  10. inline int rc() {char c=nc();while(c<'A'||c>'Z')c=nc(); return c-'A'+1;}
  11. void build_sa()
  12. {
  13. int i,j,p,*x=wa,*y=wb,*t;
  14. for(i=0;i<m;i++) Ws[i]=0;
  15. for(i=0;i<n;i++) Ws[x[i]=r[i]]++;
  16. for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
  17. for(i=n-1;~i;i--) sa[--Ws[x[i]]]=i;
  18. for(j=p=1;p<n;j<<=1,m=p)
  19. {
  20. for(p=0,i=n-j;i<n;i++) y[p++]=i;
  21. for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
  22. for(i=0;i<n;i++) wv[i]=x[y[i]];
  23. for(i=0;i<m;i++) Ws[i]=0;
  24. for(i=0;i<n;i++) Ws[wv[i]]++;
  25. for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
  26. for(i=n-1;~i;i--) sa[--Ws[wv[i]]]=y[i];
  27. for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++)
  28. {
  29. if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;
  30. else x[sa[i]]=p++;
  31. }
  32. }
  33. for(i=1;i<n;i++) rk[sa[i]]=i;
  34. for(i=p=0;i<n-1;ht[rk[i++]]=p)
  35. for(p?p--:0,j=sa[rk[i]-1];r[i+p]==r[j+p];p++);
  36. }
  37. int main()
  38. {
  39. n=rd();
  40. int i,len=n,k;
  41. for(i=0;i<n;i++) r[i]=rc();
  42. r[n]=0;
  43. for(i=n+1;i<=n+n;i++) r[i]=r[n+n-i];
  44. n<<=1; r[n++]=0;
  45. build_sa();
  46. int j=len-1; i=0;
  47. for(k=1;k<=len;k++)
  48. {
  49. if(rk[i]<rk[len+len-j]) printf("%c",r[i++]+'A'-1);
  50. else printf("%c",r[j--]+'A'-1);
  51. if(k%80==0) puts("");
  52. }
  53. return 0;
  54. }

小结:后缀数组的本质就是把所有后缀排序。好好应用这个功能会事半功倍的啊~

[bzoj1692][Usaco2007 Dec]队列变换_后缀数组_贪心的更多相关文章

  1. 【BZOJ】1692 & 1640: [Usaco2007 Dec]队列变换(后缀数组+贪心)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1692 http://www.lydsy.com/JudgeOnline/problem.php?id ...

  2. [BZOJ 1692] [Usaco2007 Dec] 队列变换 【后缀数组 + 贪心】

    ---恢复内容开始--- 题目链接:BZOJ - 1692 题目分析 首先,有个比较简单的贪心思路:如果当前剩余字符串的两端字母不同,就选取小的字母,这样显然是正确的. 然而若两端字母相同,我们怎么选 ...

  3. bzoj 1640||1692: [Usaco2007 Dec]队列变换【后缀数组】

    注意输出是80字符个一行!! 首先贪心很显然,就是两头尽量拿小的. 然后需要处理两头一样的情况,显然是选字典序小的一串,把数组反着接在原数组后面,然后跑sa,判断的时候直接比较rk数组 #includ ...

  4. bzoj1640[Usaco2007 Nov]Best Cow Line 队列变换*&&bzoj1692[Usaco2007 Dec]队列变换*

    bzoj1640[Usaco2007 Nov]Best Cow Line 队列变换 bzoj1692[Usaco2007 Dec]队列变换 题意: 有一个奶牛队列.每次可以在原来队列的首端或是尾端牵出 ...

  5. BZOJ1692: [Usaco2007 Dec]队列变换

    1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 594  Solved: 246[Submit][Sta ...

  6. [bzoj1692] [Usaco2007 Dec]队列变换 (hash||暴力)

    本题同bzoj1640...双倍经验双倍幸福 虽然数据范围n=3w然而O(n²)毫无压力= = http://blog.csdn.net/xueyifan1993/article/details/77 ...

  7. [bzoj1692][Usaco2007 Dec]队列变换——贪心+后缀数组

    Brief Description 给定一个数列,您每次可以把数列的最前面的数或最后面的数移动到新数列的开头,使得新数列字典序最小.输出这个新序列. Algorithm Design 首先我们可以使用 ...

  8. 【BZOJ1692】[Usaco2007 Dec]队列变换 后缀数组+贪心

    [BZOJ1692][Usaco2007 Dec]队列变换 Description FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”.在这场比 ...

  9. BZOJ_1692_[Usaco2007 Dec]队列变换_后缀数组

    BZOJ_1692_[Usaco2007 Dec]队列变换_后缀数组 Description FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛” ...

随机推荐

  1. WCF中的异步实现

    对于WCF中通讯的双方来说,客户端可以异步的调用服务:服务端对服务也能以异步的方式实现. 目录: 1.WCF客户端异步调用服务 2.服务端的异步实现 WCF客户端异步调用服务主要通过生成异步的代理类, ...

  2. AJPFX关于构造器的总结

    构造器        构造器定义        构造器作用        构造器特点        构造器修饰符        默认构造器        构造器重载        构造器和一般函数的区 ...

  3. yii在Windows下安装(通过composer方式)

    Composer 安装: (Composer 不是一个包管理器,它仅仅是一个依赖管理工具.它涉及 "packages" 和 "libraries",但它在每个项 ...

  4. C#方法参数关键字

    一.params关键字 prams告诉函数的调用者,该函数的参数数量是可变,如果调用函数的参数标识了params关键字,那么我们可以使用逗号分割的参数或者一个数组来作为参数: 1.这里只能是数组,Li ...

  5. Node.js——路径问题

    相对路径问题:读取文件,形如 ./ 或者 ../  一般认为这个点是相对于这个 js 文件的文件夹路径,实际上不是,这个点相对于node命令时的当前路径,不同 js 文件下进行 ./  这样的引入是不 ...

  6. 洛谷 P1886 滑动窗口 (数据与其他网站不同。。)

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  7. 今天被 <!doctype html> 搞了两个小时,两个页面同样的样式,chosen右边的小箭头,一个上下居中对齐 一个居顶对齐。最后找到问题所在doctype

    今天被 <!doctype html> 搞了两个小时,两个页面同样的样式,chosen右边的小箭头,一个上下居中对齐 一个居顶对齐.最后找到问题所在doctype <-- 这个小箭头

  8. HR教你面试时怎么谈出高工资

    不是任何时候谈钱都会伤感情,比如跟客户谈合同报价,跟房东谈房租,以及面试时和公司HR谈新工作的薪酬待遇. 这事儿一般不需要你先开口.在面试进入尾声的时候,如果HR对你还算满意,通常就会开始问你目前的薪 ...

  9. C# html table转excel

    1. protected void ebtDC_Click(object sender, EventArgs e) { string elxStr = "<table><t ...

  10. forEach的使用方法

    [-] 1  js 数组循环遍历 2  forEach 函数 3  让IE兼容forEach方法 4 如何跳出循环   1.  js 数组循环遍历. 数组循环变量,最先想到的就是 for(var i= ...