• 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 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    iris中间件
    go并发设计模式 --资源生成器模式
    Navicate
    golang sftp传输文件
    升级python
    在centos上面开机自启动某个程序
    文件MD5
    python模块之logging
    python之八大排序方法
    python生成器
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7993699.html
Copyright © 2020-2023  润新知