8.29 T1 JZOJ 100037【NOIP2017提高A组模拟7.11】后缀数组

8.29 模拟题 T2 后缀数组

对应题目 :  JZOJ 100037【NOIP2017提高A组模拟7.11】后缀数组

大概意思是说你之前获得了一个字符串,但是你现在忘了。现在你又想要知道这个字符串大小的最小值。但你现在只有那串字符串的后缀数组了,希望你能够由此求出答案。

数据有多组,n = 0 为结束标志。

Input

3

3 2 1

4

1 3 2 4

5

1 2 3 4 5

0

Output

1

3

2

那么我们要怎么做呢?其实这是一道考察我们后缀数组性质的题目。

关于后缀数组详解呢,可以参照这个:http://blog.csdn.net/yxuanwkeith/article/details/50636898

首先我们要知道关键的几个变量含义:

一是Rank,二是Sa,还有就是S。

S [ i ] 的意思是原数组中下标i ~ n 连续子串(即后缀)

Rank [ i ] 的意思是说S [ i ] 所有后缀中的排名。

Sa [ i ] 满足Suffix[SA[1]] < Suffix[SA[2]] …< Suffix[SA[Len]],即排名为i的后缀为Suffix[SA[i]] (与Rank是互逆运算)

 

然后我们观察题目,我们现在有了Sa这个数组,那么我们逆推,可以推出Rank数组对吧。

然后我们就可以使用rank[SA[i] + 1] >= rank[SA[i + 1] + 1] 这个厉害的东西。

这个东西有什么用呢?

我们可以由此推断S[SA[i]] < S[SA[i + 1]]

你看,这是不是就是我们想要的呢?

为什么呢?

我们想:

S [ 小 ]

S [ 大 ]

这样的两个东西,满足的必须条件是S [ 大 ] >= S [ 小 ] 对吧。

由于我们的要求是字符集尽量的要小,所以我们尽量去取等于的情况:

对于等于的情况呢,也就是说S [ 小 ] 以后的后缀应该要 <= S [ 大 ] 对吧。

而对应的我们观察那个厉害的东西是不是就是这么回事呢?

我们转换一下就可以发现这是等价的,所以,

对就是这么回事!

满足一个,我们就应该在 ans 上 ++,最后直接输出就好了。

还是附上一个简短的代码吧:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 100010
using namespace std;

int n;
int Sa[N],Rank[N];

int main()
{
//    freopen("sa.in","r",stdin);
//    freopen("sa.out","w",stdout);
    
    while(~scanf("%d",&n) && n != 0)
    {
        for(int i = 1; i <= n; i++) scanf("%d",&Sa[i]);
        for(int i = 1; i <= n; i++)    Rank[Sa[i]] = i;
        Rank[n+1] = 0;
        int ans = 1;
        for(int i = 1; i < n; i++)
        {
            if(Rank[Sa[i] + 1] >= Rank[Sa[i+1] + 1]) ans ++;
        }
        printf("%d
",ans);
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/sin-mo/p/7448633.html