zoukankan      html  css  js  c++  java
  • 「专题总结」后缀数组

    SA能做的事:
    1.求lcp、lcs
    2.求本质不同的子串数
    3.比较子串字典序
    4.给定子串求排名
    5.给定排名求子串
    6.求子串出现次数
    7.求多串最长公共子串
    以上“子串”意为SA处理的串的子串,可以是输入给出,然后接在后面。


    模板
    
    void SA(char *s,int m=26){
    	F(i,1,m)c[i]=0;
    	F(i,1,n)++c[x[i]=s[i]-'a'+1];
    	F(i,1,m)c[i]+=c[i-1];
    	F(i,1,n)sa[c[x[i]]--]=i;
    	for(reg int len=1,num;len<=n;len<<=1){num=0;
    		F(i,n-len+1,n)y[++num]=i;
    		F(i,1,n)if(sa[i]>len)y[++num]=sa[i]-len;
    		F(i,1,m)c[i]=0;
    		F(i,1,n)++c[x[i]];
    		F(i,1,m)c[i]+=c[i-1];
    		for(reg int i=n;i;--i)sa[c[x[y[i]]]--]=y[i];
    		F(i,1,n)y[i]=x[i],x[i]=0;
    		x[sa[1]]=m=1;
    		F(i,2,n)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+len]==y[sa[i-1]+len])?m:++m;
    		if(m==n)break;
    	}
    	F(i,1,n)rk[sa[i]]=i;
    	for(reg int i=1,k=0;i<=n;h[rk[i++]]=k,k-=k>0)
    		while(i+k<=n&&sa[rk[i]-1]+k<=n&&s[i+k]==s[sa[rk[i]-1]+k])++k;
    }
    

    A. Sandy的卡片

    把原串差分,问题转化为求N个串的最长公共子串

    trick:多串同时比较,把所有串卡在一起,并用空字符隔开。

    公共子串的相似度高,在字典上一定连续,给每个后缀打上原串标记。
    问题转化为求包含n个不同标记的区间的lcp的最大值
    显然区间缩小答案不会变差,所以用双指针在字典上扫一遍即可。

    B. 喵星球上的点名

    两个字符串代表一只喵,所以不好统计答案。
    把所有串接在一起处理SA。
    一只喵看成一种颜色,把其的两个串都染上颜色。
    对点名串二分出它作为子串的区间。
    那么第一问实质在求一个区间内有多少不同颜色,可以排序,记录pre,然后用BIT优化。同《HH的项链》
    第二问求每种颜色被多少区间包含,我不会(nlogn)。莫队比较好做,记录每种颜色进入区间的时间,然后在该颜色全部退出区间时统计存在时间即可。(然后第一问也顺便做了)

    C. 字符串

    在字典上离得近lcp肯定越优
    难点在于有区间限制,考虑主席树维护原串区间rk[i],然后树上查询rk[c]的前趋后继取最优。
    以上做法存在一定问题:有可能得出的答案超出了b的限制。考虑二分答案,在二分限制的主席树范围上进行查询。

    D. 差异

    难点在于求(sumlimits_{1 leq i < j leq n}lcp(T_i,T_j))
    所有点对的lcp,那就可以直接在h数组上统计。
    考虑(h_i)作为最小值的范围,一定是跨过(i)的一段区间。
    单调栈找到左边和右边第一个比(h_i)小的数,注意处理相同元素,方法是一边>=,一边>
    也可以直接递归建树,用RMQ快速找到最值。

    E. 相似子串

    • 给定子串rank查位置、长度
      把h数组想象成一本字典,从上到下按字典序排序。
      预处理sum数组,(sum[n]=sumlimits_{i=1}^{n}length-sa[i]+1-h[i])
      在sum上二分到子串所在区间(x),长度就是(h[x]+rank-sum[x-1])

    • 求给定位置两子串的lcp、lcs。
      正反求SA,RMQ
      或者像我一样懒,lcs暴力hash

    F. 品酒大会

    我做法很蠢,启发式合并,还有一层无用循环(nlog^2n)和bit
    「r相似」即lcp为r
    第一问:用单调栈统计,差分,最后做前缀和得答案
    第二问:RMQ预处理区间最大值和最小值,一定是最值相乘。

    G.外星联络

    求所有本质不同子串的出现顺序,按字典序输出。
    处理SA,利用h[]保留信息,优化到N^2

    H.跳蚤

    一开始的想法是区间划分dp,状态数是NK的,转移可以用三分优化,同时需要主席树。(NKlog^2N)不可做
    换个思路,最大值最小,考虑二分子串的排名。不难发现具有单调性。
    倒序check,若首字母大则return 0,否则在后边割开,划分次数大于k return 0。
    没有想到二分子串排名

    I.股市的预测

    大神题。求有多少形如ABA的串,B的长度给定
    暴力需要枚举A的位置和长度。
    枚举A的长度len,把N以len为间隔划分开,每个区间设置“关键点”,发现两端A一定会各自覆盖一个且仅一个“关键点”。
    以len为增量枚举位置i,第一个A一定只覆盖i,那么另一端j=i+m+len一定只被第二个A覆盖。
    尝试从i,j向两端扩展出区间,即求lcp和lcs,同时都要和len取min,不然一个A覆盖两个关键点,会算重。
    若lcp+lcs-(lcp&&lcs)>=len,贡献为 lcp+lcs-(lcp&&lcs)-len+1,len可以在上面滑动。
    调和级数。复杂度(nlnn)

    J.SvT

    (sum t leq 3 imes10^6)所以同样用单调栈求点对lcp,不同在于是在RMQ上做单调栈

  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/hzoi-yzh/p/12095840.html
Copyright © 2011-2022 走看看