zoukankan      html  css  js  c++  java
  • POJ 3415 Common Substrings

    本篇是罗穗骞《后缀数组——处理字符串的有力工具》的读书笔记。

    解题思路:

      先把(A, B)两个字符串连接起来,中间用一个非拉丁字母隔开,组成一个大字符串。预处理出该字符串的后缀数组和高度数组。

      扫描第一次高度数组,维护第一个单调栈,记录 (A) 的 “高度值”(lcp)(栈顶最小)和对应这个 (lcp) 的 (A) 的后缀个数 (size). 当让一个新的 (A) 的后缀的  (lcp) 入栈时,如果 (lcp) 小于栈顶,则直接入栈,(size) 为 1;否则要把栈顶元素的 (lcp) 削减到与将要入栈的 (lcp) 一样,合并到将要入栈的元素中(当然,(size) 也要合并),(contribution) 值也要减去栈顶元素的 (lcp imes size)。这个 (contribution) 值,记录的是当前的栈所维护的 (A) 的后缀遇到相应的 (B) 的后缀时能对答案做出的 “贡献值”。当扫描到 (B) 的后缀时,更新栈顶元素和 (contribution),使栈顶元素的 (lcp) 等于 (B) 的后缀所对应的 (lcp). 在最终答案中加上最新的 (contribution). 如此便可记录下 (B) 的所有的 (lcp ge K) 的后缀与其前面的 (A) 的后缀所能产生的长度不小于 K 的子串的个数。

      扫描第一遍高度数组,维护一个与上述类似的关于 (B) 的单调栈,记录 (A) 的所有的 (lcp ge K) 的后缀与其前面的 (B) 的后缀所能产生的长度不小于 K 的子串的个数。

      两遍所得的总个数之和即为答案。

    AC代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn = 2e5+10;
     7 
     8 int len,tk;
     9 int Rank[maxn],tmp[maxn];
    10 char S[maxn];
    11 int sa[maxn],lcp[maxn];
    12 bool compare_sa(int i,int j){
    13     if(Rank[i]!=Rank[j])    return Rank[i]<Rank[j];
    14     else{
    15         int ri=i+tk<=len?Rank[i+tk]:-1;
    16         int rj=j+tk<=len?Rank[j+tk]:-1;
    17         return ri<rj;
    18     }
    19 }
    20 void construct_sa(){
    21     for(int i=0;i<=len;i++){
    22         sa[i]=i;
    23         Rank[i]=i<len?S[i]:-1;
    24     }
    25     for(tk=1;tk<=len;tk*=2){
    26         sort(sa,sa+len+1,compare_sa);
    27         tmp[sa[0]]=0;
    28         for(int i=1;i<=len;i++){
    29             tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
    30         }
    31         for(int i=0;i<=len;i++){
    32             Rank[i]=tmp[i];
    33         }
    34     }
    35 }
    36 void construct_lcp(){
    37     int h=0;
    38     lcp[0]=0;
    39     for(int i=0;i<len;i++){
    40         int j=sa[Rank[i]-1];
    41         if(h>0) h--;
    42         for(;j+h<len&&i+h<len;h++){
    43             if(S[j+h]!=S[i+h])  break;
    44         }
    45         lcp[Rank[i]-1]=h;
    46     }
    47 }
    48 int K,len1,len2;
    49 char A[maxn],B[maxn];
    50 ll Stack[2][maxn]; //Stack[0] 记录lcp; Stack[1] 记录个数。
    51 ll solve(bool flag){  //1,栈维护 A 的后缀;0,栈维护 B 的后缀。
    52     ll ret=0;
    53     int top=0;  //top 指向栈顶
    54     ll contribution=0;
    55     for(int i=0;i<len;i++){
    56         if(lcp[i]<K){
    57             top=contribution=0; //清空栈
    58         }
    59         else{
    60             int Size=0;
    61             if((sa[i]<len1&&flag)||(sa[i]>len1&&!flag)){    //说明这个元素需要入栈
    62                 Size=1;
    63                 contribution+=(lcp[i]-K+1);
    64             }
    65             while(top>0&&lcp[i]<=Stack[0][top-1]){
    66                 top--;
    67                 contribution-=Stack[1][top]*(Stack[0][top]-lcp[i]);
    68                 Size+=Stack[1][top];
    69             }
    70             if(Size){
    71                 Stack[0][top]=lcp[i];
    72                 Stack[1][top]=Size;
    73                 top++;
    74             }
    75             if((sa[i+1]>len1&&flag)||(sa[i+1]<len1&&!flag))
    76                 ret+=contribution;
    77         }
    78     }
    79     return ret;
    80 }
    81 int main(){
    82     while(scanf("%d",&K)==1&&K){
    83         scanf("%s",A);
    84         scanf("%s",B);
    85         len1=strlen(A),len2=strlen(B);
    86         len=len1+len2+1;
    87         int ind=0;
    88         for(int i=0;i<len1;i++,ind++)   S[ind]=A[i];
    89         S[ind++]='#';
    90         for(int i=0;i<len2;i++,ind++)   S[ind]=B[i];
    91         construct_sa();
    92         construct_lcp();
    93         printf("%lld
    ",solve(1)+solve(0));
    94     }
    95     return 0;
    96 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    HTML5 GeoLocation 地理定位
    HTML5 LocalStorage 本地存储
    JS-事件代理(委托)
    面向对象(封装、继承、多态)
    js图片预加载
    jQuery 事件
    svn无法验证
    Ext.data.Store(转)
    ExtJS实现Excel导出(转)
    <![CDATA[ ]]> 意思
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7993699.html
Copyright © 2011-2022 走看看