• 后缀数组


    感觉跟字符串有关的算法都难飞了:)

    首先入坑是noi day2t2,舔题解开启后缀数组副本

    • 首先自然是模板题刷水,因为(爱情怎莫会有沧桑)懒,所以没写过基数排序,所以舔模板也舔地十分困难,最后还是跪求zl老爷讲解,,,然而当时也是美得朦胧。。。

       不过还好之前舔了集训队论文->算法合集之《后缀数组——处理字符串的有力工具》

       

     1 #include<stdio.h>
     2 #include<string.h>
     3 #define maxn 100005
     4 char str[maxn];
     5 int sa[maxn],x[maxn],y[maxn],tong[maxn],rank[maxn],h[maxn];
     6 bool cmp(int *nxt,int a,int b,int l){
     7     return nxt[a]==nxt[b]&&nxt[a+l]==nxt[b+l];
     8 }
     9 void SA(int n,int m){
    10     int i,j,*cur=x,*nxt=y,*t,p;
    11     for(i=0;i<m;i++)tong[i]=0;
    12     for(i=0;i<n;i++)tong[cur[i]=str[i]]++;
    13     for(i=1;i<m;i++)tong[i]+=tong[i-1];
    14     for(i=n-1;i>=0;i--)sa[--tong[cur[i]]]=i;
    15     
    16     for(j=1,p=1;p<n;j*=2,m=p){
    17         
    18         for(i=n-j,p=0;i<n;i++)nxt[p++]=i;
    19         for(i=0;i<n;i++)if(sa[i]>=j)nxt[p++]=sa[i]-j;
    20         
    21         for(i=0;i<m;i++)tong[i]=0;
    22         for(i=0;i<n;i++)tong[cur[nxt[i]]]++;
    23         for(i=1;i<m;i++)tong[i]+=tong[i-1];
    24         for(i=n-1;i>=0;i--)sa[--tong[cur[nxt[i]]]]=nxt[i];
    25         for(t=cur,cur=nxt,nxt=t,p=1,cur[sa[0]]=0,i=1;i<n;i++)
    26             cur[sa[i]]=cmp(nxt,sa[i-1],sa[i],j)?p-1:p++;
    27     }
    28 }
    29 void calheight(int n){
    30     int i,j,k=0;
    31     for(i=1;i<=n;i++)rank[sa[i]]=i;
    32     for(i=0;i<n;h[rank[i++]]=k)
    33         for(k?k--:0,j=sa[rank[i]-1];str[i+k]==str[j+k];k++);
    34 }
    35 int main(){
    36     freopen("1.in","r",stdin);
    37     scanf("%s",str);
    38     int n=strlen(str);
    39     str[n]=0;
    40     SA(n+1,128);
    41     for(int i=1;i<=n;i++)printf("%d ",sa[i]+1);
    42     printf("
    ");
    43     calheight(n);
    44     for(int i=2;i<=n;i++)printf("%d ",h[i]);
    45     return 0;
    46 }

         代码的核心就是那三个空行,,,把SA函数分成了四个部分

         ①是处理长度为1的字符的大小关系

         ②是倍增循环2^j里的j

         ③是根据上层的sa数组排第二关键字,nxt里放的就是按第二关键字排好序的第一关键字对应位置,,,其实就是图中的斜杠对应的竖杠。。。

         ④是对第一关键字的排序,cmp是允许编号重复

       tips:论文里的wv数组被老夫给压了(小机房日常之比谁代码短),然而gst大爷说不压会更快,所以之后的某篇里会出现haha数组。。。

      既然有课件于是就按着刷呗 

    • 最长公共前缀,即lcp(suffix(i),suffix(j))=min{height[k]|i+1≤k≤j},RMQ处理
    • 可重叠最长重复子串,即求height数组里的最大值即可,因为任意两个后缀的最长公共前缀都是height数组里某一段的最小值,那么这个值一定不大于height数组里的最大值
    • 不可重叠最长重复子串,二分,划分区间,判断是否相交

        poj1743

            

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 #define maxn 20005
     6 int str[maxn],sa[maxn],rank[maxn],height[maxn],x[maxn],y[maxn],tong[maxn];
     7 
     8 bool cmp(int *nxt,int a,int b,int j){
     9     return nxt[a]==nxt[b]&&nxt[a+j]==nxt[b+j];
    10 }
    11 void SA(int n,int m){
    12     int i,j,p,*cur=x,*nxt=y,*t;
    13     for(i=0;i<m;i++)tong[i]=0;
    14     for(i=0;i<n;i++)tong[cur[i]=str[i]]++;
    15     for(i=1;i<m;i++)tong[i]+=tong[i-1];
    16     for(i=n-1;i>=0;i--)sa[--tong[cur[i]]]=i;
    17 
    18     for(p=1,j=1;p<n;j*=2,m=p){
    19     
    20         for(p=0,i=n-j;i<n;i++)nxt[p++]=i;
    21         for(i=0;i<n;i++)if(sa[i]>=j)nxt[p++]=sa[i]-j;
    22 
    23         for(i=0;i<m;i++)tong[i]=0;
    24         for(i=0;i<n;i++)tong[cur[nxt[i]]]++;
    25         for(i=1;i<m;i++)tong[i]+=tong[i-1];
    26         for(i=n-1;i>=0;i--)sa[--tong[cur[nxt[i]]]]=nxt[i];
    27         for(t=cur,cur=nxt,nxt=t,p=1,cur[sa[0]]=0,i=1;i<n;i++)
    28             cur[sa[i]]=cmp(nxt,sa[i-1],sa[i],j)?p-1:p++;
    29     }
    30 }
    31 void calheight(int n){
    32     int i,j,k=0;
    33     for(i=1;i<=n;i++)rank[sa[i]]=i;
    34     for(i=0;i<n;height[rank[i++]]=k)
    35         for(k?k--:0,j=sa[rank[i]-1];str[i+k]==str[j+k];k++);
    36 }
    37 bool can(int x,int n){
    38     int i=2,maxp,minp;
    39     while(1){
    40         while(i<=n&&height[i]<x)i++;
    41         if(i>n)break;
    42         maxp=sa[i-1];
    43         minp=sa[i-1];
    44         while(i<=n&&height[i]>=x){
    45             maxp=max(maxp,sa[i]);
    46             minp=min(minp,sa[i]);
    47             i++;
    48         }
    49         if(maxp-minp>=x)return true;
    50     }
    51     return false;
    52 }
    53 int main(){
    54     //freopen("1.in","r",stdin);
    55     while(1){
    56         int n;
    57         scanf("%d",&n);
    58     if(!n)break;
    59     for(int i=0;i<n;i++)scanf("%d",&str[i]);
    60         if(n<10){
    61             printf("0
    ");
    62             continue;
    63         }
    64         n--;
    65         for(int i=0;i<n;i++)str[i]=str[i+1]-str[i]+89;
    66         str[n]=0;
    67         SA(n+1,200);
    68         calheight(n);
    69         int l=0,r=n/2+1;
    70         while(l<r-1){
    71             int mid=(l+r)>>1;
    72             if(can(mid,n))l=mid;
    73             else r=mid;
    74         }
    75         l=l<4?0:l+1;
    76         printf("%d
    ",l);
    77     }
    78     return 0;
    79 }

         tips:①因为一个子串加减一个值与原子串视为同一个,所以要用差值来计算,还要映射为正数

             ②当n=1时要特判,或者与n<10的情况一起判掉

    • 可重叠的k次最长重复子串,同上,只不过判断条件变成了划分的元素个数与k的关系

             poj3261

          没撒可注意的,m有点大,不会写快排版的烧饼就只能离散咯(波浪号

            

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 #define maxn 20005
     6 #define fir first
     7 #define sec second
     8 pair<int,int>cow[maxn];
     9 int str[maxn],sa[maxn],rank[maxn],height[maxn],x[maxn],y[maxn],tong[maxn];
    10 
    11 bool cmp(int *nxt,int a,int b,int j){
    12     return nxt[a]==nxt[b]&&nxt[a+j]==nxt[b+j];
    13 }
    14 void SA(int n,int m){
    15     int i,j,p,*cur=x,*nxt=y,*t;
    16     for(i=0;i<m;i++)tong[i]=0;
    17     for(i=0;i<n;i++)tong[cur[i]=str[i]]++;
    18     for(i=1;i<m;i++)tong[i]+=tong[i-1];
    19     for(i=n-1;i>=0;i--)sa[--tong[cur[i]]]=i;
    20 
    21     for(p=1,j=1;p<n;j*=2,m=p){
    22         
    23         for(p=0,i=n-j;i<n;i++)nxt[p++]=i;
    24         for(i=0;i<n;i++)if(sa[i]>=j)nxt[p++]=sa[i]-j;
    25 
    26         for(i=0;i<m;i++)tong[i]=0;
    27         for(i=0;i<n;i++)tong[cur[nxt[i]]]++;
    28         for(i=1;i<m;i++)tong[i]+=tong[i-1];
    29         for(i=n-1;i>=0;i--)sa[--tong[cur[nxt[i]]]]=nxt[i];
    30         for(t=cur,cur=nxt,nxt=t,p=1,cur[sa[0]]=0,i=1;i<n;i++)
    31             cur[sa[i]]=cmp(nxt,sa[i-1],sa[i],j)?p-1:p++;
    32     }
    33 }
    34 void calheight(int n){
    35     int i,j,k=0;
    36     for(i=1;i<=n;i++)rank[sa[i]]=i;
    37     for(i=0;i<n;height[rank[i++]]=k)
    38         for(k?k--:0,j=sa[rank[i]-1];str[i+k]==str[j+k];k++);
    39 }
    40 bool can(int x,int n,int k){
    41     int i=2;
    42     while(1){
    43         while(i<=n&&height[i]<x)i++;
    44         if(i>n)break;
    45         int num=1;
    46         while(i<=n&&height[i]>=x)num++,i++;
    47         if(num>=k)return true;
    48     }
    49     return false;
    50 }
    51 int main(){
    52     freopen("1.in","r",stdin);
    53     int n,k;
    54     scanf("%d%d",&n,&k);
    55     for(int i=0;i<n;i++){
    56         scanf("%d",&cow[i].fir);
    57         cow[i].sec=i;
    58     }
    59     sort(cow,cow+n);
    60     int m=1;
    61     str[cow[0].sec]=m;
    62     for(int i=1;i<n;i++){
    63         if(cow[i].fir!=cow[i-1].fir)m++;
    64         str[cow[i].sec]=m;
    65     }
    66     str[n]=0;
    67     SA(n+1,m+1);
    68     calheight(n);
    69     int l=0,r=n;
    70     while(l<r-1){
    71         int mid=(l+r)>>1;
    72         if(can(mid,n,k))l=mid;
    73         else r=mid;
    74     }
    75     printf("%d
    ",l);
    76     return 0;
    77 }
  • 相关阅读:
    反射
    IDEA配置数据库
    配置idea的maven镜像为aliyun
    蓝桥---芯片测试(思维)
    汉诺塔(思维、DP思想)
    立方数(质因子、优化)
    碎碎念(DP)
    牛牛战队的比赛地(三分)
    子段乘积(尺取、逆元)
    子段异或(位运算)
  • 原文地址:https://www.cnblogs.com/Ngshily/p/4976443.html
Copyright © 2020-2023  润新知