zoukankan      html  css  js  c++  java
  • POJ 1743 Musical Theme(后缀数组)

    http://poj.org/problem?id=1743

    题意:
    给定一个字符串,求最长重复子串,可以是完全相等,也可以是每一位相减都相等,并且这两个子串不能重叠。

    思路:

    先二分答案,把题目变成判定性问题:判断是否存在两个长度为 k 的子串是相同的,且不重叠。解决这个问题的关键还是利用height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的 height 值都不小于 k。

    分完组后,寻找每组当中sa值的最大值和最小值,只要相减>k那么就是满足的,这点很容易想吧。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<vector>
      6 #include<stack>
      7 #include<queue>
      8 #include<cmath>
      9 #include<map>
     10 #include<set>
     11 using namespace std;
     12 typedef long long ll;
     13 typedef pair<int,int> pll;
     14 const int INF = 0x3f3f3f3f;
     15 const int maxn=40000+5;
     16 
     17 int s[maxn];
     18 int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
     19 int Rank[maxn],height[maxn];
     20 
     21 void build_sa(int m)
     22 {
     23     int *x=t,*y=t2;
     24     //基数排序
     25     for(int i=0;i<m;i++)    c[i]=0;
     26     for(int i=0;i<n;i++)    c[x[i]=s[i]]++;
     27     for(int i=1;i<m;i++)    c[i]+=c[i-1];
     28     for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
     29     for(int k=1;k<=n;k<<=1)
     30     {
     31         int p=0;
     32         //直接利用sa数组排序第二关键字
     33         for(int i=n-k;i<n;i++)  y[p++]=i;
     34         for(int i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;
     35         //基数排序第一关键字
     36         for(int i=0;i<m;i++)    c[i]=0;
     37         for(int i=0;i<n;i++)    c[x[y[i]]]++;
     38         for(int i=1;i<m;i++)    c[i]+=c[i-1];
     39         for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
     40         //根据sa和y计算新的x数组
     41         swap(x,y);
     42         p=1;
     43         x[sa[0]]=0;
     44         for(int i=1;i<n;i++)
     45             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
     46         if(p>=n)
     47             break;
     48         m=p;                //下次基数排序的最大值
     49     }
     50 }
     51 
     52 void getHeight()
     53 {
     54     int i,j,k=0;
     55     for(i=1;i<n;i++)  Rank[sa[i]]=i;
     56     for(i=0;i<n-1;i++)  
     57     {
     58         if(k)  k--;
     59         int j=sa[Rank[i]-1];
     60         while(s[i+k]==s[j+k])  k++;
     61         height[Rank[i]]=k;
     62     }
     63 }
     64 
     65 bool check(int k)
     66 {
     67     int mi=INF,mx=-INF;
     68     for(int i=2;i<=n-1;i++)
     69     {
     70         if(height[i]>=k)
     71         {
     72             mi=min(mi,min(sa[i],sa[i-1]));
     73             mx=max(mx,max(sa[i],sa[i-1]));
     74             if(mx-mi>k) return true;
     75         }
     76         else
     77         {
     78             mi=INF;
     79             mx=-INF;
     80         }
     81     }
     82     return false;
     83 }
     84 
     85 int main()
     86 {
     87     //freopen("in.txt","r",stdin);
     88     while(~scanf("%d",&n) && n)
     89     {
     90         for(int i=0;i<n;i++) scanf("%d",&s[i]);
     91         for(int i=0;i<n-1;i++)  s[i]=s[i+1]-s[i]+88;
     92         s[n-1]=0;
     93         build_sa(200);
     94         getHeight();
     95         int ans=0;
     96         int l=4,r=n;
     97         while(l<=r)
     98         {
     99             int mid=(l+r)>>1;
    100             if(check(mid)) {ans=mid;l=mid+1;}
    101             else r=mid-1;
    102         }
    103         ans++;
    104         printf("%d
    ",ans<5?0:ans);
    105     }
    106     return 0;
    107 }
  • 相关阅读:
    如何反编译Python写的exe到py
    Liunx常用查找,授权,启动命令
    判断ArrayList集合内是否包含某个元素
    SpringApplicationBuilder作用,以及设置跨域请求过滤器,字符编码,打war包用tomcat运行
    JSON数据解析:Gson(谷歌)和fastjson(阿里巴巴)的异同
    转载:docker安装mycat
    转载:sqlserver 开启快照
    windows 开启操作系统审核策略功能,并设置日志保留不少于180天
    mysql数据库表同步命令
    macos 忘记开机密码,重设密码
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7573180.html
Copyright © 2011-2022 走看看