• 【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 }

    贴一下代码啦。

  • 相关阅读:
    提高你的Java代码质量吧:使用构造函数协助描述枚举项
    Python文件或目录操作的常用函数
    汉语-词语:胸怀
    汉语-词语:胸襟
    汉语-词语:谋略
    汉语-词语:气量
    植物-常见树木:刺槐
    植物-常见树木:楝
    HDU 2255 奔小康赚大钱 KM算法题解
    Dozer--第三方复制工具,哎哟,还不错!
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5869027.html
Copyright © 2020-2023  润新知