zoukankan      html  css  js  c++  java
  • BZOJ 4566 JZYZOJ 1547 [haoi2016T5]找相同子串 后缀数组 并查集

    http://172.20.6.3/Problem_Show.asp?id=1547

    http://www.lydsy.com/JudgeOnline/problem.php?id=4566

    单纯后缀数组是O(n^2)应该是40分

    似乎后缀自动机是正解。

    但是后缀数组+并查集也可以乱搞a掉,这里写的是并查集写法,也算是get了一个并查集的用法,某种意义上并查集可以用来维护区间最大值最小值的贡献,实现方法见代码。

    定义字符串大小的整型变量时候,

    char siz;

    导致re什么的,

    我大概是个zz。

    顺便存个板子,抄紫萱学姐的板子。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 const int maxn=200010;
     8 const int pl=50;
     9 int sa[maxn*2+pl]={};//排名第i的是从sa[i]开始的数组
    10 int rk[maxn*2+pl]={};//i的排名
    11 int height[maxn*2+pl]={};//排名第i的与排名第i-1的最长相同前缀长度
    12 int temp[maxn*2+pl]={};//暂时的排名
    13 int cnt[maxn*2+pl]={};//第i种(字典序)前缀的有多少个(的前缀和)
    14 int p[maxn*2+pl]={};//临时对这一次需要用的sa的储存,处理了后缀长度不同的情况。
    15 char ch[maxn*2+pl]={},ch1[maxn]={},ch2[maxn]={};
    16 int siz1,siz2,siz;
    17 int fa[maxn*2+pl]={},a[maxn*2+pl]={},lef[maxn*2+pl]={},rig[maxn*2+pl]={};
    18 inline bool equ(int x,int y,int l){return rk[x]==rk[y]&&rk[x+l]==rk[y+l];}
    19 void SA(){
    20     for(int i=1;i<=siz;i++)rk[i]=ch[i],sa[i]=i;
    21     for(int i,sig=255,l=0,pos=0;pos<siz;sig=pos){//l从0开始是预处理
    22         pos=0;
    23         for(i=siz-l+1;i<=siz;i++)p[++pos]=i;
    24         for(i=1;i<=siz;i++)if(sa[i]>l)p[++pos]=sa[i]-l;
    25         for(i=0;i<=sig;i++)cnt[i]=0;
    26         for(i=1;i<=siz;i++)cnt[rk[p[i]]]++;
    27         for(i=1;i<=sig;i++)cnt[i]+=cnt[i-1];
    28         for(i=siz;i>0;i--){sa[cnt[rk[p[i]]]]=p[i];cnt[rk[p[i]]]--;}
    29         pos=0;
    30         for(i=1;i<=siz;i++){
    31             if(equ(sa[i],sa[i-1],l))temp[sa[i]]=pos ;
    32             else temp[sa[i]]=++pos;
    33         }for(i=1;i<=siz;i++)rk[i]=temp[i];
    34         if(l==0)l=1;
    35         else l<<=1;
    36     }
    37     for(int i=1,k=0;i<=siz;i++){
    38         /*对于每一个位置的后缀,下一个位置的后缀可匹配的最短长度
    39         一定大于等于该位置可匹配的长度-1,显然。所以是O(n)的算法
    40         */
    41         if(rk[i]==1){k=0;continue;}
    42         if(k>0)k--;
    43         int j=sa[rk[i]-1];
    44         while(ch[i+k]==ch[j+k])k++;
    45         height[rk[i]]=k;
    46     }
    47 }
    48 bool mcmp(int x,int y){return height[x]>height[y];}
    49 int getfa(int x){
    50     if(x!=fa[x])fa[x]=getfa(fa[x]);
    51     return fa[x];
    52 }
    53 int main(){
    54     //freopen("a.in","r",stdin);
    55     scanf("%s",&ch1);siz1=strlen(ch1);
    56     scanf("%s",&ch2);siz2=strlen(ch2);
    57     ch[siz1+1]='z'+1;siz=siz1+siz2+1;
    58     for(int i=0;i<siz1;i++)ch[i+1]=ch1[i];
    59     for(int i=0;i<siz2;i++)ch[siz1+2+i]=ch2[i];
    60     SA();
    61     for(int i=1;i<=siz;i++){
    62         a[i]=fa[i]=i;
    63         lef[i]=(sa[i]<=siz1);
    64         rig[i]=1^lef[i];
    65     }sort(a+1,a+1+siz,mcmp);
    66     long long ans=0;
    67     int x,y;
    68     for(int i=1;i<=siz;i++){
    69         if(a[i]==1)continue;
    70         x=getfa(a[i]);y=getfa(a[i]-1);
    71         ans+=(long long)height[a[i]]*(long long)(lef[x]*rig[y]+rig[x]*lef[y]);
    72         lef[x]+=lef[y];rig[x]+=rig[y];fa[y]=x;
    73     }printf("%lld
    ",ans);
    74     return 0;
    75 }
    View Code

    更新:http://www.cnblogs.com/137shoebills/p/8511439.html 这是一道板子题的代码,注释应该被我完善了,更加清晰一点,所以我为什么要先写一道组合题再写板子啊喂。

  • 相关阅读:
    linux目录结构
    php程序员要懂那些linux知识?
    树和二叉树
    linux学习课程
    顺序栈的实现
    编写一个插件(前面JavaScript高级总结)
    javascript高级课程-4
    字符串的顺序表
    js 万年历实现
    利用 postMessage 进行数据传递 (iframe 及web worker)及问题
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8508295.html
Copyright © 2011-2022 走看看