• POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)


    洛谷P2743传送门

    题目大意:给你一个序列,求其中最长的一对相似等长子串

    一对合法的相似子串被定义为:

    1.任意一个子串长度都大于等于5

    2.不能有重叠部分

    3.其中一个子串可以在全部+/-某个值后和另一个串完全相同

    还是老套路了,其实只要求出每一项和前一项的差值序列,这样第三个问题可以被转化为求最长不重叠的相同子串,最后把答案+1就行了

    这道题竟然还是LTC大佬的男人八题!正解是后缀数组+二分,但据说可以n^2骗分过

    思路是先求出height数组,对于排序后的字符串集合有一个神奇的性质,如果有某连续的几个字符串height>=x,那么这几个字符串的公共前缀长度>=x,可以用Trie树的思想很容易地证明

    那现在就要解决第二个问题,不能有重叠部分

    直接求解不容易,所以我们二分答案去做,每次二分出一个答案x,然后去height数组里找,把连续的几个height>=x字符串想象成一块,那么如果这个块合法,这一块内一定存在两个字符串的sa[i]-sa[j]>=x,也就是在这一块内找出sa[i]的最大最小值就行啦

    复杂度O(nlogn)

    傻了吧唧的把后缀数组敲错了,调了半个小时

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N 20010
     5 #define inf 0x3f3f3f3f
     6 #define maxn 100
     7 using namespace std;
     8 
     9 int n,len;
    10 int a[N],b[N],tr[N],rk[N],sa[N],hs[N],h[N];
    11 int gint()
    12 {
    13     int rett=0,fh=1;char c=getchar();
    14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    15     while(c>='0'&&c<='9'){rett=(rett<<3)+(rett<<1)+c-'0';c=getchar();}
    16     return rett*fh;
    17 }
    18 void clr()
    19 {
    20     memset(a,0,sizeof(a));memset(tr,0,sizeof(tr));
    21     memset(b,0,sizeof(b));memset(rk,0,sizeof(rk));
    22     memset(h,0,sizeof(h));memset(sa,0,sizeof(sa));
    23     memset(hs,0,sizeof(hs));
    24 }
    25 bool check(int k,int x,int y){
    26     if(x+k>len||y+k>len) return 0;
    27     else return (rk[x]==rk[y]&&rk[x+k]==rk[y+k])?1:0;
    28 }
    29 void get_sa()
    30 {
    31     int cnt=0,i=0;
    32     for(i=1;i<=n;i++) hs[b[i]]++;
    33     for(i=1;i<=2*maxn;i++) if(hs[i]) tr[i]=++cnt;
    34     for(i=1;i<=2*maxn;i++) hs[i]+=hs[i-1];
    35     for(i=1;i<=n;i++) rk[i]=tr[b[i]],sa[hs[b[i]]--]=i;
    36     for(int k=1;cnt<len;k<<=1)
    37     {
    38         for(i=1;i<=cnt;i++) hs[i]=0;
    39         for(i=1;i<=len;i++) hs[rk[i]]++;
    40         for(i=1;i<=cnt;i++) hs[i]+=hs[i-1];
    41         for(i=len;i>=1;i--) if(sa[i]>k) tr[sa[i]-k]=hs[rk[sa[i]-k]]--;
    42         for(i=1;i<=k;i++) tr[len-i+1]=hs[rk[len-i+1]]--;
    43         for(i=1;i<=len;i++) sa[tr[i]]=i;
    44         for(i=1,cnt=0;i<=len;i++) tr[sa[i]]=check(k,sa[i],sa[i-1])?cnt:++cnt;
    45         for(i=1;i<=len;i++) rk[i]=tr[i];
    46     }
    47 }
    48 void get_height()
    49 {
    50     for(int i=1;i<=len;i++){
    51         if(rk[i]==1) continue;
    52         for(int j=max(1,h[rk[i-1]]-1);j;j++)
    53             if(b[i+j-1]==b[sa[rk[i]-1]+j-1]) h[rk[i]]=j;
    54             else break;
    55     }
    56 }
    57 bool check(int ans)
    58 {
    59     int i=1,j=1;
    60     for(i=1;i<=len;)
    61     {
    62         if(h[i]<ans) {i++;continue;}
    63         int mi=sa[i-1],ma=sa[i-1];
    64         for(;h[i]>=ans&&i<=len;i++)
    65         {
    66             mi=min(mi,sa[i]);
    67             ma=max(ma,sa[i]);
    68             if(ma-mi>ans) return 1;
    69         }
    70     }return 0;
    71 }
    72 
    73 int main()
    74 {
    75     while(scanf("%d",&n)&&n!=0)
    76     {
    77         len=n;
    78         clr();
    79         for(int i=1;i<=n;i++)
    80             a[i]=gint(),b[i]=a[i]-a[i-1]+maxn;
    81         get_sa();
    82         get_height();
    83         int l=0,r=n,ans=0;
    84         while(l<=r){
    85             int mid=(l+r)>>1;
    86             if(check(mid)) ans=mid,l=mid+1;
    87             else r=mid-1;
    88         }
    89         if(ans<4) printf("0
    ");
    90         else printf("%d
    ",ans+1);
    91     }
    92     return 0;
    93 }
  • 相关阅读:
    PHP的学习--在sublime中使用XDebug(Ubuntu)
    Yii的学习(4)--Active Record
    Yii的学习(3)--查询生成器 (Query Builder)
    数据可视化(9)--数据可视化6步法
    HTML5的学习--performance获取加载时间的工具
    HTML5的学习--performance
    存储过程之三—语句
    存储过程之二—变量
    数据库自定义函数
    存储过程之一—建立简单的存储过程
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9697158.html
Copyright © 2020-2023  润新知