题目描述

小敏和小燕是一对好朋友。
他们正在玩一种神奇的游戏,叫Minecraft。
他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。
 
 
前几天刚A掉的题..
一看题目就后缀数组敲起来了..贴一贴代码~
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define INF 1000000007
#define N 1200010
using namespace std;
int n,a[N],s[N],tmp[N],rank[N],sa[N];
void suffix_array(){
    int sz=N;
    for (int i=0;i<n;i++) rank[i]=a[i];
    for (int i=0;i<sz;i++) s[i]=0;
    for (int i=0;i<n;i++) s[rank[i]]++;
    for (int i=1;i<sz;i++) s[i]+=s[i-1];
    for (int i=n-1;i>=0;i--) sa[--s[rank[i]]]=i;
    for (int j=1;j<=n/4;j*=2){
        int p=0;
        for (int i=n-j;i<n;i++) tmp[p++]=i;
        for (int i=0;i<n;i++) if (sa[i]-j>=0) tmp[p++]=sa[i]-j;
        for (int i=0;i<sz;i++) s[i]=0;
        for (int i=0;i<n;i++) s[rank[i]]++;
        for (int i=1;i<sz;i++) s[i]+=s[i-1];
        for (int i=n-1;i>=0;i--) sa[--s[rank[tmp[i]]]]=tmp[i];
        p=0;tmp[sa[0]]=0;
        for (int i=1;i<n;i++){
            int v0=sa[i-1],v1=sa[i],v00,v01;
            if (v0+j<n) v00=rank[v0+j];else v00=-1;
            if (v1+j<n) v01=rank[v1+j];else v01=-1;
            if (rank[v0]==rank[v1]&&v00==v01) tmp[sa[i]]=p;else tmp[sa[i]]=++p;
        }
        for (int i=0;i<n;i++) rank[i]=tmp[i];
    }
}
int main(){
    scanf("%d",&n);
    for (int i=0;i<4*n;i++) a[i]=N/2;
    for (int i=0;i<n;i++) scanf("%d",&a[i]),a[n+i]=a[i];
    n*=4;suffix_array();    
    for (int i=sa[0];i-sa[0]<(n/4)-1;i++) printf("%d ",a[i]);
    printf("%d",a[sa[0]+(n/4)-1]);
    return 0;
}
 
讲得很清楚很容易理解 但是等写完了以后才发现居然这么神奇~
 
一个长度为n的字符串s,假设其最小表示为s[M(s)..n]+s[1..M(s)-1]
只需要维护一个指针i使得i<=M(s)总成立并且逐渐接近M(s),以及一个用来辅助的指针j并且保证i<j
我的理解j的目的是在i的位置以后试图找到一个优于i的表示
并且如果存在这样一个优于i的表示的起始点p,满足j<=p
这样在情况②和④的时候似乎才说得通一些
为了保证每个表示都在字符串中出现一次,我们令s=s+s
 
开始时指针的状态为i,j,一直向右匹配直到其失配位置假设此时指针滑过k个位置
s[i..i+k-1]=s[j..j+k-1]且s[i+k]>s[j+k]时
显然i..i+k都不能为最小表示的起始位置,因为都可以在j..j+k中找到对应的且优于它的表示
因此i+k+1位置仍能保证<=M(s)
s[i..i+k-1]=s[j..j+k-1]且s[i+k]<s[j+k]时,与①类似可得到
以j+t为起点的表示一定劣于以i+t为起点的表示(t∈[0,k])
而当前指针指向j这个位置,根据指针j的定义可知,i+1..j-1中存在比i更优的表示已被排除,所以可以进一步得到
以j+t为起点的表示一定劣于以i为起点的表示(t∈[0,k])
所以j+k+1位置仍满足指针j的性质
 
大致情况与①相同,当s[i+k]>s[j+k]且i+k+1<j时
显然i+1..j-1中已经不可能存在比i更优的表示,所以i可以直接滑到j
 
在①③两种情况中,i指针移动之后j指针指向的位置变为i+1
 
什么时候结束?
(1)j指针指向了>n的位置,也就意味着i+1..n间不存在比i更优的表示了
   此时i指针指向的位置就是字符串最小表示的起始点!
(2)j+k>2*n
  s[i..i+k-1]=s[j..j+k-1]
  以j+t为起始点的表示不优于以i+t为起始点的表示(j+t<=n)
  以i..j-1为起始点的表示不优于以i为起始点的表示
  根据上面两条就可以同样得到此时i指针指向的位置就是字符串最小表示的起始点!
 

 
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,a[600010];
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[n+i]=a[i];
    int i,j;
    for (i=1,j=2;j<=n;){
        int k=0;
        while (j+k<=2*n&&a[i+k]==a[j+k]) k++;
        if (j+k>2*n) break;
        if (a[i+k]>a[j+k]) i=max(j,i+k+1),j=i+1;else j=j+k+1;
    }
    for (int j=0;j<n-1;j++) printf("%d ",a[j+i]);printf("%d",a[i+n-1]);
}
 
 
 
 不论时间还是代码长度上都有很大的改进~
 
 
 
 
 
 

【BZOJ2882】【字符串的最小表示】工艺的更多相关文章

  1. POJ 2406 Power Strings(字符串的最小循环节)

    题目链接:http://poj.org/problem?id=2406 题意:确定字符串最多是多少个相同的字串重复连接而成的 思路:关键是找到字符串的最小循环节 code: #include < ...

  2. kmp的next数组的运用(求字符串的最小循环节)

    hdu3746 Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  3. POJ 1509 Glass Beads 后缀自动机 模板 字符串的最小表示

    http://poj.org/problem?id=1509 后缀自动机其实就是一个压缩储存空间时间(对节点重复利用)的储存所有一个字符串所有子串的trie树,如果想不起来长什么样子可以百度一下找个图 ...

  4. 字符串的最小最大表示法O(n)

    以下介绍内容内容转自:http://blog.csdn.net/zy691357966/article/details/39854359 网上看了这篇文章后还是感觉有些地方讲的没有详细的证明所以添加了 ...

  5. UVA.455 Periodic Strings(字符串的最小周期)

    Periodic Strings 模板 题意分析 判断字符串的最小周期 代码总览 /* Title:UVA.455 Author:pengwill Date:2016-12-16 */ #includ ...

  6. hnuun 11544 小明的烦恼——找字符串(求环形字符串的最小最大字典序)

    http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11544&courseid=0 最小最大表示法: 求环 ...

  7. Leetcode之动态规划(DP)专题-712. 两个字符串的最小ASCII删除和(Minimum ASCII Delete Sum for Two Strings)

    Leetcode之动态规划(DP)专题-712. 两个字符串的最小ASCII删除和(Minimum ASCII Delete Sum for Two Strings) 给定两个字符串s1, s2,找到 ...

  8. Java实现 LeetCode 712 两个字符串的最小ASCII删除和(最长公共子串&&ASCII值最小)

    712. 两个字符串的最小ASCII删除和 给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和. 示例 1: 输入: s1 = "sea", s2 ...

  9. HDU 4162 Shape Number(字符串,最小表示法)

    HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[ ...

随机推荐

  1. Maven基本理解

    转 maven(一) maven到底是个啥玩意~ 我记得在搞懂maven之前看了几次重复的maven的教学视频.不知道是自己悟性太低还是怎么滴,就是搞不清楚,现在弄清楚了,基本上入门了.写该篇博文,就 ...

  2. Win2019 + Oracle18c SQLPLUS 命令行出现乱码的解决

    1. Win2019 中文版 安装了 Oracle数据库, dbca 建库时选择的 的字符集是 ZHS16GBK 然后发现使用sqlplus 时有乱码的现象如图示: 2. csdn 上面有一个博客有解 ...

  3. IF与SWITCH

    今晚刚刚看了一点儿<大话设计模式>这本书,看到它示例的第一个程序,好像有点理解IF与SWITCH的区别了.大致的思考了总结出来. IF适用于每个条件都必须判断,就是IF语句中的判断是不同类 ...

  4. 运维堡垒机----Gateone

    简介: 运维堡垒机的理念起源于跳板机.2000年左右,高端行业用户为了对运维人员的远程登录进行集中管理,会在机房里部署跳板机.跳板机就是一台服务器,维护人员在维护过程中,首先要统一登录到这台服务器上, ...

  5. Linux下修改环境变量PATH

    1.什么是环境变量(PATH) 在Linux中,在执行命令时,系统会按照PATH的设置,去每个PATH定义的路径下搜索执行文件,先搜索到的文件先执行. 我们知道查阅文件属性的指令ls 完整文件名为:/ ...

  6. 51nod 1682 中位数计数(差分统计)

    中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数. 现在有n个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数. 首先,显 ...

  7. 【bzoj4425】[Nwerc2015]Assigning Workstations分配工作站 贪心+堆

    题目描述 佩内洛普是新建立的超级计算机的管理员中的一员. 她的工作是分配工作站给到这里来运行他们的计算研究任务的研究人员. 佩内洛普非常懒惰,不喜欢为到达的研究者们解锁机器. 她可以从在她的办公桌远程 ...

  8. 移动端开发-viewport

    1.viewport viewport 即设备 屏幕上显示网页的区域.因为移动设备屏幕比较小,为了能让移动设备能够显示更多内容,默认设置的viewport 并不是屏幕真是像素点的宽度,一般为980px ...

  9. CSS预处理语言-less 的使用

    Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量.Mixin.函数等特性,使 CSS 更易维护和扩展. Less 可以运行在 Node 或浏览器端. Less的编译处理 作为一 ...

  10. PHP关于VC9和VC6以及Thread Safe和Non Thread Safe版本选择的问题

    一.如何选择PHP5.3的VC9版本和VC6版本 VC6版本是使用Visual Studio 6编译器编译的,如果你的PHP是用Apache来架设的,那你就选择VC6版本.      VC9版本是使用 ...