• POJ 1743 (后缀数组 二分) Musical Theme


    看来对height数组进行分段确实是个比较常用的技巧。

    题意:

    一个主题是可以变调的,也就是如果这个主题所有数字加上或者减少相同的数值,可以看做是相同的主题。

    一个主题在原串中至少要出现两次,而且一定要有不相交的两次。

    因为说了可以变调,所以我们处理每相邻两项的差值,这样就得到n-1个数字。然后找最大的不相交重复的连续子序列即可。

    找这样的子序列还是要二分子序列的长度k,然后根据k对height进行分段,如果某一段的最大的sa值与最小的sa值相差超过k的话便符合要求。

    然后强调一下几个容易出错的地方:

    • 前面说一定要超过k才行,下面解释下为什么等于k是不可以的。比如说n=5, 序列为 0 3 8 11 16.求出相邻两项的差值为3 5 3 5,很明显子序列3 5是一个不相交的重复序列,但是第一个3 5 对应原序列的0 3 8,第二个3 5 对应原序列的 8 11 16. 显然,这有重叠的部分了。
    • 我们在求出相邻两项差值的序列中找到最长不相交子序列后,假设长度为k,那么对应原序列中子序列的长度为k + 1
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 20000 + 10;
      7 const int INF = 1000000000;
      8 int n;
      9 
     10 struct SuffixArray
     11 {
     12     int s[maxn];
     13     int sa[maxn];
     14     int rank[maxn];
     15     int height[maxn];
     16     int t[maxn], t2[maxn], c[maxn];
     17     int n;
     18 
     19     void clear() { n = 0; memset(sa, 0, sizeof(sa)); }
     20 
     21     void build_sa(int m)
     22     {
     23         int i, *x = t, *y = t2;
     24         for(i = 0; i < m; i++) c[i] = 0;
     25         for(i = 0; i < n; i++) c[x[i] = s[i]]++;
     26         for(i = 1; i < m; i++) c[i] += c[i - 1];
     27         for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
     28         for(int k = 1; k <= n; k <<= 1)
     29         {
     30             int p = 0;
     31             for(i = n - k; i < n; i++) y[p++] = i;
     32             for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
     33             for(i = 0; i < m; i++) c[i] = 0;
     34             for(i = 0; i < n; i++) c[x[y[i]]]++;
     35             for(i = 1; i < m; i++) c[i] += c[i - 1];
     36             for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
     37             swap(x, y);
     38             p = 1; x[sa[0]] = 0;
     39             for(i = 1; i < n; i++)
     40                 x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++;
     41             if(p >= n) break;
     42             m = p;
     43         }
     44     }
     45 
     46     void build_height()
     47     {
     48         int i, j, k = 0;
     49         for(i = 0; i < n; i++) rank[sa[i]] = i;
     50         for(i = 0; i < n; i++)
     51         {
     52             if(k) k--;
     53             j = sa[rank[i] - 1];
     54             while(s[i + k] == s[j + k]) k++;
     55             height[rank[i]] = k;
     56         }
     57     }
     58 };
     59 
     60 SuffixArray sa;
     61 
     62 bool ok(int len)
     63 {
     64     int Max, Min;
     65     Max = Min = sa.sa[0];
     66     for(int i = 1; i < n; i++)
     67     {
     68         if(sa.height[i] < len) Max = Min = sa.sa[i];
     69         else
     70         {
     71             Max = max(Max, sa.sa[i]);
     72             Min = min(Min, sa.sa[i]);
     73             if(Max - Min > len) return true;
     74         }
     75     }
     76     return false;
     77 }
     78 
     79 int solve()
     80 {
     81     int L = 1, R = n / 2, M;
     82     while(L < R)
     83     {
     84         M = (L + R + 1) / 2;
     85         if(ok(M)) L = M;
     86         else R = M - 1;
     87     }
     88     return L;
     89 }
     90 
     91 int main()
     92 {
     93     //freopen("in.txt", "r", stdin);
     94 
     95     while(scanf("%d", &n) == 1 && n)
     96     {
     97         sa.clear();
     98 
     99         int pre, now; scanf("%d", &pre);
    100         n--;
    101         for(int i = 0; i < n; i++)
    102         {
    103             scanf("%d", &now);
    104             sa.s[i] = now - pre + 100;
    105             pre = now;
    106         }
    107         sa.s[n] = 0;
    108         sa.n = n;
    109         sa.build_sa(200);
    110         sa.build_height();
    111         int ans = solve();
    112         printf("%d
    ", ans >= 4 ? ans + 1 : 0);
    113     }
    114 
    115     return 0;
    116 }
    代码君
  • 相关阅读:
    316 Remove Duplicate Letters 去除重复字母
    315 Count of Smaller Numbers After Self 计算右侧小于当前元素的个数
    313 Super Ugly Number 超级丑数
    312 Burst Balloons 戳气球
    309 Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期
    Java 类成员的初始化顺序
    JavaScript 全局
    HTML字符实体
    Java中的toString()方法
    JavaScript 弹窗
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4443667.html
Copyright © 2020-2023  润新知