zoukankan      html  css  js  c++  java
  • POJ 1743 Musical Theme

    POJ_1743

        搜到的题解基本都是说去找最长的不重叠的重复的子串,但是我一直对题目描述里面的那个const带有一点纠结,比如88 88 88 1 1 1 88 88 88 1 1 1,我觉得要按const去理解的话应该输出3的,但题解都是输出的6。不过意在练后缀数组的使用,就没有太顾及这些问题了。

        这个题目关键的地方有两个:第一,重复的子串一定可以看作是某两个后缀的公共前缀,第二,把题目转化成去判定对于任意的一个长度k,是否存在长度至少为k的不重叠的重复的子串。

        转化成判定问题之后,就可以二分去解答了。在验证判定是否正确时,我们可以把相邻的所有不小于k的height[]看成一组,然后去看每个组内sa[]值的最大值与最小值之差是否满足大于等于k,如果有某一组满足这个条件,那么在这个组内就一定可以找到长度不小于k且不重叠的重复的子串。

        因为排名第i的字符串和排名第j的字符串的最长公共前缀等于height[i],height[i+1],...,height[j]中的最小值,所以把所有不小于k的height[]看成一组就保证了组内任意两个字符串的最长公共前缀都至少为k。其中最有可能形成不重叠的重复的子串就是组内sa[]值最大的字符串与sa[]值最小的字符串。

        对于后缀数组的倍增算法的代码上的一些理解,看以参考我的另外一篇文章:http://www.cnblogs.com/staginner/archive/2012/02/02/2335600.html

    #include<stdio.h>
    #include<string.h>
    #define MAXD 20010
    #define INF 0x3f3f3f3f
    int N, height[MAXD], rank[MAXD], sa[MAXD], r[MAXD], wa[MAXD], wb[MAXD], ws[MAXD], wv[MAXD];
    void init()
    {
    int i, j, k;
    for(i = 0; i < N; i ++)
    scanf("%d", &r[i]);
    for(i = N - 1; i > 0; i --)
    r[i] = r[i] - r[i - 1] + 90;
    r[0] = 1, r[N] = 0;
    }
    int cmp(int *p, int x, int y, int l)
    {
    return p[x] == p[y] && p[x + l] == p[y + l];
    }
    void da(int n, int m)
    {
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i ++)
    ws[i] = 0;
    for(i = 0; i < n; i ++)
    ++ ws[x[i] = r[i]];
    for(i = 1; i < m; i ++)
    ws[i] += ws[i - 1];
    for(i = n - 1; i >= 0; i --)
    sa[-- ws[x[i]]] = i;
    for(p = 1, j = 1; p < n; j *= 2, m = p)
    {
    for(p = 0, i = n - j; i < n; i ++)
    y[p ++] = i;
    for(i = 0; i < n; i ++)
    if(sa[i] >= j)
    y[p ++] = sa[i] - j;
    for(i = 0; i < n; i ++)
    wv[i] = x[y[i]];
    for(i = 0; i < m; i ++)
    ws[i] = 0;
    for(i = 0; i < n; i ++)
    ++ ws[wv[i]];
    for(i = 1; i < m; i ++)
    ws[i] += ws[i - 1];
    for(i = n - 1; i >= 0; i --)
    sa[-- ws[wv[i]]] = y[i];
    for(t = x, x = y, y = t, x[sa[0]] = 0, p = 1, i = 1; i < n; i ++)
    x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p ++;
    }
    }
    void calheight(int n)
    {
    int i, j, k = 0;
    for(i = 1; i <= n; i ++)
    rank[sa[i]] = i;
    for(i = 0; i < n; height[rank[i ++]] = k)
    for(k ? -- k : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k ++);
    }
    void solve()
    {
    int i, j, mid, min, max, minr, maxr, ok;
    da(N + 1, 200);
    calheight(N);
    min = 3, max = N / 2 + 1;
    for(;;)
    {
    mid = (max + min) / 2;
    if(mid == min)
    break;
    ok = 0, minr = INF, maxr = -1;
    for(i = 1; i <= N; i ++)
    {
    if(height[i] < mid)
    minr = maxr = sa[i];
    else
    {
    if(sa[i] < minr)
    minr = sa[i];
    if(sa[i] > maxr)
    maxr = sa[i];
    if(maxr - minr >= mid)
    {
    ok = 1;
    break;
    }
    }
    }
    if(ok)
    min = mid;
    else
    max = mid;
    }
    if(mid > 3)
    printf("%d\n", mid + 1);
    else
    printf("0\n");
    }
    int main()
    {
    for(;;)
    {
    scanf("%d", &N);
    if(!N)
    break;
    init();
    if(N < 10)
    printf("0\n");
    else
    solve();
    }
    return 0;
    }


  • 相关阅读:
    浅谈 Linux 下的 SSH1, SSH2
    jquery replace方法去空格
    CakePHP Configure::read('KHCITY') 数据配置读取
    php中::是什么意思?
    CakePHP redirect函数
    Redis介绍
    Microsoft Dynamics CRM 2011 面向Internet部署 (IFD) ADFS虚拟机环境搭建的步骤(CRM与ADFS装在同一台服务器上) 摘自网络
    [Windows Server] 在 Windows Server 2012 上安裝 .NET Framework 3.5
    Solution for When browse http://xxx/ReportServer Show Error (rsAccessDenied)
    Windows Server 2008 R2 配置AD(Active Directory)域控制器 -zhai zi wangluo
  • 原文地址:https://www.cnblogs.com/staginner/p/2337299.html
Copyright © 2011-2022 走看看