zoukankan      html  css  js  c++  java
  • 【bzoj4310/hdu5030-跳蚤】后缀数组

    我真的是。。调了一百年。。

    傻逼的人生。。

    而且这题好像可以用sam做哎!我Y出了一个奇怪的办法。。

    好吧sam是不能做这题的。搞错了。

    说说后缀数组好了。。

    搞后缀数组

    然后我们要二分一个子串,判断是否有一种划分方法,满足划分出来的所有串的最大子串不超过这个串。

    二分是第now个后缀

    二分第now个多长的前缀

    ————确定了一个子串

    首先,这题具有单调性,而且是求最大串最小,所以我们可以二分答案串。

      怎么二分答案串呢,我们不是已经用后缀数组求出了sa数组吗,sa数组表示的串是排过序的,其中每个后缀的前缀子串大小按长度的递增而递增,所以可以在sa数组里面二分。(我是先二分后缀,再二分长度)
      然后是判断,怎么判断是不是可以划分成至多k个串使他们都不超过二分串。
      还是在sa上做。
      如果他的sa位置小于mid,那么不用管,因为它怎么样都是小于二分串的。
      如果他的sa位置大于等于mid,而且他跟二分串没有LCP,那么这个二分一定没有答案,因为最小二分都使他不符合。
      除此之外,求出sa位置大于等于mid的所有串跟二分串的LCP,在sa[i]~sa[i]+lcp-1的位置上一定要至少打一个标记,因为不打标记它就会比二分串大了。
      
      所以最后我们会得到很多个区间,在这些区间里面至多打k-1个标记,使得每个区间中有含有一个标记。
     
      转化成了这样,就很容易做了。貌似是smg区间覆盖之类的问题。排个序,去个重,判断+累加一下就可以了。
     
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 
      9 const int N=100100,Inf=(int)1e9;
     10 int K,n,cl,ed,r[N],h[N],t[N],rk[N],Rs[N],sa[N],y[N],wr[N];
     11 char c[N];
     12 
     13 int minn(int x,int y){return x<y ? x:y;}
     14 
     15 void get_sa(int m)
     16 {
     17     for(int i=1;i<=cl;i++) rk[i]=c[i]-'a'+1;
     18     for(int i=1;i<=m;i++) Rs[i]=0;
     19     for(int i=1;i<=cl;i++) Rs[rk[i]]++;
     20     for(int i=2;i<=m;i++) Rs[i]+=Rs[i-1];
     21     for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;//debug
     22     
     23     int ln=1,p=0;
     24     while(p<cl)
     25     {
     26         int k=0;
     27         for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
     28         for(int i=1;i<=cl;i++) 
     29             if(sa[i]>ln) y[++k]=sa[i]-ln;
     30         for(int i=1;i<=cl;i++) wr[i]=rk[y[i]];
     31         
     32         for(int i=1;i<=m;i++) Rs[i]=0;
     33         for(int i=1;i<=cl;i++) Rs[wr[i]]++;
     34         for(int i=2;i<=m;i++) Rs[i]+=Rs[i-1];
     35         for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];//debug
     36         
     37         for(int i=1;i<=cl;i++) wr[i]=rk[i];
     38         for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
     39         rk[sa[1]]=1;
     40         p=1;
     41         for(int i=2;i<=cl;i++)
     42         {
     43             if(wr[sa[i]]!=wr[sa[i-1]] || wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
     44             rk[sa[i]]=p;
     45         }
     46         ln*=2;m=p;
     47     // for(int i=1;i<=cl;i++) printf("%d ",rk[i]);printf("
    ");
     48     // for(int i=1;i<=cl;i++) printf("%d ",sa[i]);printf("
    ");
     49     }
     50     sa[0]=rk[0]=0;
     51 }
     52 
     53 void get_h()
     54 {
     55     int k=0;
     56     for(int i=1;i<=cl;i++) if(rk[i]!=1)
     57     {
     58         int j=sa[rk[i]-1];
     59         if(k) k--;
     60         while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++;
     61         h[rk[i]]=k;
     62     }
     63     h[1]=0;
     64 }
     65 
     66 bool ok(int ll,int rr)
     67 {
     68     int k=rr-ll+1;
     69     memset(t,0,sizeof(t));
     70     memset(r,0,sizeof(r));
     71     for(int i=rk[ll];i<=cl;i++)
     72     {
     73         if(i!=rk[ll]) k=minn(k,h[i]);
     74         else if(rr==cl) continue;
     75         if(k==0) return 0;
     76         if(t[sa[i]]==0 || sa[i]+k-1<t[sa[i]]) t[sa[i]]=sa[i]+k-1;
     77     }
     78     int pl=0,pr=0,cut,ans;
     79     for(int i=cl;i>=1;i--)
     80     {
     81         if(!t[i]) continue;
     82         if(!pr) {pr=i;continue;}
     83         if(pr<=t[i]) t[i]=0;
     84         pr=t[i];
     85     }
     86     for(int i=1;i<=cl;i++) if(t[i]) r[t[i]]=i;
     87     pl=0,pr=0,cut=0,ans=0;
     88     for(int i=cl;i>=1;i--)
     89     {
     90         if(!r[i]) continue;
     91         if(!pl) {pl=r[i],pr=i;cut=r[i];ans++;continue;}
     92         if(i<pl) cut=r[i],ans++;
     93         if(pl<=i && i<=pr) 
     94         {
     95             if(!(cut>=r[i] && cut<=i)) cut=r[i],ans++;
     96         }
     97         pl=r[i],pr=i;
     98     }
     99     if(ans<=K-1) return 1;
    100     return 0;
    101 }
    102 
    103 int check(int now)
    104 {
    105     int ll=sa[now]+h[now],rr=cl,mid;
    106     while(ll<=rr)
    107     {
    108         mid=(ll+rr)/2;
    109         if(ok(sa[now],mid)) 
    110         {
    111             rr=mid;
    112             if(ll==rr) return ll;
    113         }
    114         else ll=mid+1;
    115     }
    116     if(ll<=rr) return ll;
    117     return 0;
    118 }
    119 
    120 int main()
    121 {
    122     // freopen("a.in","r",stdin);
    123     freopen("magic.in","r",stdin);
    124     freopen("magic.out","w",stdout);
    125     scanf("%d",&K);
    126     scanf("%s",c+1);
    127     cl=strlen(c+1);
    128     get_sa(26);
    129     get_h();
    130     int ll=1,rr=cl,mid,now;
    131     while(ll<rr)
    132     {
    133         mid=(ll+rr)/2;
    134         now=check(mid);
    135         if(now) rr=mid,ed=now;
    136         else ll=mid+1;
    137     }
    138     if(ll) 
    139     {
    140         for(int i=sa[ll];i<=ed;i++) printf("%c",c[i]);printf("
    ");
    141     }
    142     return 0;
    143 }

    贴一下代码啦。

  • 相关阅读:
    eclipse下c/cpp " undefined reference to " or "launch failed binary not found"问题
    blockdev 设置文件预读大小
    宝宝语录
    CentOS修改主机名(hostname)
    subprocess报No such file or directory
    用ldap方式访问AD域的的错误解释
    英特尔的VTd技术是什么?
    This virtual machine requires the VMware keyboard support driver which is not installed
    Linux内核的文件预读详细详解
    UNP总结 Chapter 26~29 线程、IP选项、原始套接字、数据链路访问
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5869027.html
Copyright © 2011-2022 走看看