• 字符串(后缀数组):POJ 3415 Common Substrings


    Common Substrings
     

    Description

    A substring of a string T is defined as:

    T(i, k)=TiTi+1...Ti+k-1, 1≤ii+k-1≤|T|.

    Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):

    S = {(i, j, k) | kK, A(i, k)=B(j, k)}.

    You are to give the value of |S| for specific A, B and K.

    Input

    The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.

    1 ≤ |A|, |B| ≤ 105
    1 ≤ Kmin{|A|, |B|}
    Characters of A and B are all Latin letters.

    Output

    For each case, output an integer |S|.

    Sample Input

    2
    aababaa
    abaabaa
    1
    xx
    xx
    0
    

    Sample Output

    22
    5
      这道题呃,有些考验程序实践能力。
      题意:对于给定的两个字符串和一个整数K,求两个字符串长度大于等于K的公共子串数目。
      将两个字符串接起来,中间用一个特殊字符隔开,枚举Lcp,暴力枚举是O(n³)的,死活都不可能过。
      这是我们想:能否使用以前枚举的信息?所以正解就出来了:单调栈优化!
      具体咋打就看代码吧~~~


      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 using namespace std;
      5 const int maxn=400010;
      6 char S[maxn];
      7 int sa[maxn],r[maxn],rank[maxn],lcp[maxn];
      8 int Wv[maxn],Ws[maxn],Wa[maxn],Wb[maxn],len;
      9 
     10 bool cmp(int *p,int a,int b,int l){
     11     return p[a]==p[b]&&p[a+l]==p[b+l];
     12 }
     13 
     14 void DA(int n,int m){
     15     int i,j,p,*x=Wa,*y=Wb,*t;
     16     for(i=0;i<m;i++)Ws[i]=0;
     17     for(i=0;i<n;i++)++Ws[x[i]=r[i]];
     18     for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
     19     for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;
     20     
     21     for(j=1,p=1;p<n;m=p,j<<=1){
     22         for(p=0,i=n-j;i<n;i++)y[p++]=i;
     23         for(i=0;i<n;i++)
     24             if(sa[i]>=j)
     25                 y[p++]=sa[i]-j;
     26         
     27         for(i=0;i<m;i++)Ws[i]=0;
     28         for(i=0;i<n;i++)++Ws[Wv[i]=x[y[i]]];
     29         for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
     30         for(i=n-1;i>=0;i--)
     31             sa[--Ws[Wv[i]]]=y[i];
     32         
     33         for(t=x,x=y,y=t,i=1,p=1,x[sa[0]]=0;i<n;i++)
     34             x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
     35     }
     36 }
     37 
     38 void Lcp(int n){
     39     int i,j,k=0;
     40     for(i=1;i<=n;i++)rank[sa[i]]=i;
     41     for(i=0;i<n;lcp[rank[i++]]=k)
     42         for(k?--k:k,j=sa[rank[i]-1];r[i+k]==r[j+k];++k);
     43 }
     44 
     45 int s[maxn][2];
     46 
     47 int main(){
     48     int n,k;
     49     while(~scanf("%d",&k)&&k){
     50         scanf("%s",S);
     51         n=strlen(S);S[n]='%';
     52         scanf("%s",S+n+1);
     53         len=strlen(S);
     54         for(int i=0;i<len;i++)
     55             r[i]=S[i];
     56         r[len]=0;
     57         DA(len+1,128);
     58         Lcp(len);
     59         
     60         int cnt=0;
     61         long long ans=0,sum=0;
     62         for(int i=1;i<=len;i++){
     63             if(lcp[i]<k){
     64                 sum=0;cnt=0;
     65                 continue;
     66             }
     67             int tot=0;
     68             if(sa[i-1]>n){
     69                 sum+=lcp[i]-k+1;
     70                 tot++;
     71             }
     72             while(cnt&&s[cnt][0]>=lcp[i]){
     73                 tot+=s[cnt][1];
     74                 sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]);
     75                 cnt--;
     76             }
     77             s[++cnt][0]=lcp[i];
     78             s[cnt][1]=tot;    
     79             if(sa[i]<n)ans+=sum;
     80         }
     81         cnt=0;sum=0;
     82         for(int i=1;i<=len;i++){
     83             if(lcp[i]<k){
     84                 sum=0;cnt=0;
     85                 continue;
     86             }
     87             int tot=0;
     88             if(sa[i-1]<n){
     89                 sum+=lcp[i]-k+1;
     90                 tot++;
     91             }
     92             while(cnt&&s[cnt][0]>=lcp[i]){
     93                 tot+=s[cnt][1];
     94                 sum-=1ll*s[cnt][1]*(s[cnt][0]-lcp[i]);
     95                 cnt--;
     96             }
     97             s[++cnt][0]=lcp[i];
     98             s[cnt][1]=tot;    
     99             if(sa[i]>n)ans+=sum;
    100         }        
    101         printf("%lld
    ",ans);
    102     }
    103     return 0;
    104 }

    尽最大的努力,做最好的自己!
  • 相关阅读:
    linux下安装nginx
    Java8聚合操作
    redis持久化选项
    初探redis缓存击穿、穿透、雪崩问题
    Java8lambda表达式
    Java8方法引用
    java8并行计算
    Start Developing iOS Apps Today(中文)
    C#/mono开发Android应用程序入门(二)第一个应用程序(Hello World)(转)
    win8各种开发问题收集及解决
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5293934.html
Copyright © 2020-2023  润新知