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;
    }


  • 相关阅读:
    Leetcode:linked_list_cycle
    关于Go语言共享内存操作的小实例
    程序猿如同妓女
    算法——排序算法个人总结
    CentOS 6.4下安装和配置Samba 第2页_服务器应用_Linux公社-Linux系统门户网站
    解决fedora samba在windows下无权限访问的问题
    基于samba实现win7与linux之间共享文件_阳仔_新浪博客
    增加samba用户提示Failed to add entry for user
    Ubuntu+Win7+Samba实现文件共享_Linux教程_Linux公社-Linux系统门户网站
    Mycat 月分片方法
  • 原文地址:https://www.cnblogs.com/staginner/p/2337299.html
Copyright © 2011-2022 走看看