zoukankan      html  css  js  c++  java
  • [USACO5.1] Musical Themes

    后缀数组求最长重复且不重叠子串。

    poj 1743 传送门

    洛谷 P2743 传送门

    1.子串可以“变调”(即1 3 6和3 5 8视作相同)。解决办法:求字符串相邻元素的差形成新串。用新字符串求解最长重复子串即可。

    2.最长重复子串不能重叠。解决办法:用sa数组判断开始位置。

    倍增答案即可,从1到n枚举height,记录子串开始的最左端、最右端。

    如果找到了两个后缀,其公共前缀长度大于k,且其开始位置之间的间隔大于k,就满足条件。

    由height数组的性质可得:要使x、y的公共前缀长度大于k,则需要h[x+1]、h[x+2]......h[y]全部大于k。

    所以只要有一个没有大于k,就得重新开始。即:重置子串开始的最左端、最右端。

    最后答案需要+1,并判断是否大于等于5(题意要求)。

    注意poj的数据范围比洛谷上大,而且有多组测试数据。

    下面只给出poj1743的代码。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int n,ans;
     7 int s[20005];
     8 int sa[20005],rk[20005];
     9 int tr[20005],h[20005];
    10 
    11 int cmp(int x,int y,int k)
    12 {
    13     if(x+k>n||y+k>n)return 0;
    14     return rk[x]==rk[y]&&rk[x+k]==rk[y+k];
    15 }
    16 
    17 void cal()
    18 {
    19     int i,cnt;
    20     for(i=1;i<=n;i++)h[s[i]]++;
    21     for(cnt=0,i=1;i<=200;i++)if(h[i])tr[i]=++cnt;
    22     for(i=1;i<=200;i++)h[i]+=h[i-1];
    23     for(i=1;i<=n;i++)rk[i]=tr[s[i]],sa[h[s[i]]--]=i;
    24     for(int k=1;cnt!=n;k<<=1)
    25     {
    26         for(i=1;i<=n;i++)h[i]=0;
    27         for(i=1;i<=n;i++)h[rk[i]]++;
    28         for(i=1;i<=n;i++)h[i]+=h[i-1];
    29         for(i=n;i;i--)if(sa[i]>k)tr[sa[i]-k]=h[rk[sa[i]-k]]--;
    30         for(i=1;i<=k;i++)tr[n-i+1]=h[rk[n-i+1]]--;
    31         for(i=1;i<=n;i++)sa[tr[i]]=i;
    32         for(cnt=0,i=1;i<=n;i++)tr[sa[i]]=cmp(sa[i],sa[i-1],k)?cnt:++cnt;
    33         for(i=1;i<=n;i++)rk[i]=tr[i];
    34     }
    35     for(i=1;i<=n;i++)h[i]=0;
    36     for(i=1;i<=n;i++)
    37     {
    38         if(rk[i]==1)continue;
    39         for(int j=max(1,h[rk[i-1]]-1);;j++)
    40         {
    41             if(s[i+j-1]==s[sa[rk[i]-1]+j-1])h[rk[i]]=j;
    42             else break;
    43         }
    44     }
    45 }
    46 
    47 int check(int k)
    48 {
    49     if(k>n)return 0;
    50     int l,r;
    51     l=r=sa[1];
    52     for(int i=2;i<=n;i++)
    53     {
    54         if(h[i]>=k)
    55         {
    56             l=min(l,sa[i]);
    57             r=max(r,sa[i]);
    58             if(r-l>k)return 1;
    59         }else l=r=sa[i];
    60     }
    61     return 0;
    62 }
    63 
    64 int main()
    65 {
    66     scanf("%d",&n);
    67     while(n)
    68     {
    69         memset(h,0,sizeof(h));
    70         memset(tr,0,sizeof(tr));
    71         memset(rk,0,sizeof(rk));
    72         memset(sa,0,sizeof(sa));
    73         ans=0;
    74         for(int i=1;i<=n;i++)scanf("%d",&s[i]);
    75         for(int i=1;i<n;i++)s[i]=s[i+1]-s[i]+90;
    76         cal();
    77         for(int i=20;i>=0;i--)
    78             if(check(ans|(1<<i)))ans|=(1<<i);
    79         ans=(ans+1)>=5?(ans+1):0;
    80         printf("%d
    ",ans);
    81         scanf("%d",&n);
    82     }
    83     return 0;
    84 }
  • 相关阅读:
    每日一题力扣520 判断大小写
    每日一题力扣434
    每日一题力扣557
    每日一题力扣344 反转字符串
    每日一题力扣125 回文字符串
    每日一题力扣541
    每日一题力扣58
    【20211015】项目成本粗略分析
    【20211013】连岳摘抄
    【20211014】自己就是解决问题的起点
  • 原文地址:https://www.cnblogs.com/cervusy/p/9714864.html
Copyright © 2011-2022 走看看