• [bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)


    以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= =

    定义(来自关于后缀数组的那篇国家集训队论文。。)

    后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列SA[1],SA[2],……,SA[n],并且保证Suffix(SA[i])<Suffix(SA[i+1]),1≤i<n。

         也就是将S的n个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入SA中。

    height数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。

     

    接着是许昊然在《数据结构漫谈》中的讲解//原谅我不知道复制文字的正确技巧QAQ

    听起来(而且事实上)的确挺简单的= =

    最感人的是反正前面复杂度都已经O(n log²n)了。。。后面就随便玩了反正超时了也是前面的锅。。。

    然而复杂度实在是有点虚。。。虽然本题n才2w,但是OJ上跑了600+ms。。。。。似乎还是数据随机的情况下

    如果是较极限的数据(似乎没什么区别。。)的话10w的数据范围学校机子要跑3s。。。。

    然后删掉取模,让它自然溢出的话似乎大概也许可能是在1s内跑出来的吧。。。。。。。。事实证明n=10w时要1.5s左右= =QAQ//学校机子1s内能循环2亿次= =

    综上。。。我选择相信测评姬(捂脸

    SA数组和height数组造出来后这题就是《后缀数组——处理字符串的有力工具》里面的例题了= =

    诶好像有点详略不当

    引用部分原文:

      先二分答案为mid,把题目变成判定性问题。

        解决这个问题的关键还是利用height数组。把排序后的后缀分成若干组,其中每组的后缀之间的height值都不小于mid(最长公共前缀长度不小于mid的两个后缀一定在同一组)。

        判断有没有一个组的后缀个数不小于k即可。

     

    傻逼代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=20012;
    struct zs{
        int pos;
    }sa[maxn];
    int s[maxn];
    ll pre[maxn],modd,jc[maxn],val1,val2;
    int l,r,mid,i,j,k,n,m,now,nowlen,K;
    int h[maxn];
    inline int getlen(int s1,int s2){//求两后缀(分别从s1,s2开始)的最长公共前缀的长度 
        if(s[s1]!=s[s2])return 0;
        int l=1,r=n-max(s1,s2)+1,mid;
        while(l<r){
            mid=(l+r+1)>>1;
            val1=pre[s1+mid-1]-pre[s1-1]*jc[mid]%modd;
            val2=pre[s2+mid-1]-pre[s2-1]*jc[mid]%modd;
            if(val1<0)val1+=modd;if(val2<0)val2+=modd;
            if(val1==val2)l=mid;else r=mid-1;
        }
        return l;
    }
    inline bool bigger(int s1,int s2){
        if(s[s1]!=s[s2])return s[s1]>s[s2];
        int len=getlen(s1,s2);
        if(len==n-max(s1,s2)+1)
            return s1<s2;
        return s[s1+len]>s[s2+len];
    }
    bool cmp(zs a,zs b){
        return !bigger(a.pos,b.pos);
    }
    int main(){
        scanf("%d%d",&n,&K);
        for(i=1;i<=n;i++)scanf("%d",&s[i]);
        modd=1233333333;
        jc[0]=1;
        for(i=1;i<=n;i++)jc[i]=jc[i-1]*197%modd,pre[i]=(pre[i-1]*197%modd+s[i])%modd;/
        for(i=1;i<=n;i++)sa[i].pos=i;
        sort(sa+1,sa+1+n,cmp);
        for(i=2;i<=n;i++)h[i]=getlen(sa[i].pos,sa[i-1].pos);
        l=0;r=n;
        while(l<r){
            mid=(l+r+1)>>1;
            now=1;nowlen=0;
            for(i=2;i<=n+1&&nowlen<K;i++)if(h[i]<mid)nowlen=max(nowlen,i-now),now=i;
            if(nowlen<K)r=mid-1;else l=mid;
        }
        printf("%d
    ",l);
        return 0;
    }
    View Code
  • 相关阅读:
    KVM安装之脚本和镜像目录树准备
    KVM安装之网桥
    安装KVM虚拟机步骤
    NFS搭建配置
    为项目组搭建开发测试环境介绍
    VMWare虚拟机copy后网卡不是eth0解决办法
    安装Oracle 10g和SQLServer2008(仅作学习使用VirtualBox虚拟机来安装节省电脑资源)
    常用的SQL语句
    在web项目中集成Spring
    IOC容器装配Bean(注解方式)
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/4989723.html
Copyright © 2020-2023  润新知