• 【bzoj4310】跳蚤


    • 题解:

      • 读了半个小时题。。。首先明确题意:求$S$分成至多$k$个串,每个串的子串的最大字典序的最大字典序(要选两次最大)最小
      • 求出sa和ht,本质不同的子串的个数等于总个数减去$sa$里面前后相同的个数:$sum = sum len - sa[i] - ht[i] $
      • 因为在后缀数组中本质相同的子串一定出现在$sa$的连续一段的$lcp$里;
      • 二分本质不同的串为第mid个,可以利用上面的结论$O(n)$求出第mid个串是什么;
      • 从后往前贪心,能不放就不放,比较两个串可以先求$lcp$再$O(1)$比较
      • 所以是$O(N logN)$的
         1 #include<cstdio>
         2 #include<iostream>
         3 #include<cstring>
         4 #define Run(i,l,r) for(int i=l;i<=r;i++)
         5 #define Don(i,l,r) for(int i=l;i>=r;i--)
         6 using namespace std;
         7 typedef long long ll;
         8 const int N=100010;
         9 int n,k,m,sa[N],ht[N],rk[N],c[N],x[N],y[N],b[N],f[N][20],lg[N],ansl,ansr;
        10 char s[N];
        11 void build_sa(){
        12     m=128;
        13     for(int i=0;i<m;i++) c[i]=0;
        14     for(int i=0;i<n;i++) c[x[i]=s[i]]++;
        15     for(int i=1;i<m;i++) c[i]+=c[i-1];
        16     for(int i=n-1;~i;i--) sa[--c[x[i]]]=i;
        17     int p;
        18     //for(int i=0;i<n;i++) cout<<sa[i]<<endl;cout<<endl;
        19     for(int k=1;k<n;k<<=1){
        20         p=0;
        21         for(int i=n-k;i<n;i++) y[p++]=i;
        22         for(int i=0;i<n;i++) if(sa[i]>=k)y[p++]=sa[i]-k;
        23         for(int i=0;i<m;i++) c[i]=0;
        24         for(int i=0;i<n;i++) c[x[y[i]]]++;
        25         for(int i=1;i<m;i++) c[i]+=c[i-1];
        26         for(int i=n-1;~i;i--) sa[--c[x[y[i]]]]=y[i];
        27         swap(x,y); p=1;x[sa[0]]=0;
        28         for(int i=1;i<n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p-1:p++;
        29         if(p>=n) break; 
        30         m=p+1;
        31     //    for(int i=0;i<n;i++) cout<<sa[i]<<endl;cout<<endl;
        32     }
        33 }////////////////
        34 void build_ht(){
        35     for(int i=0;i<n;i++)rk[sa[i]]=i;
        36     for(int i=0,k=0,j;i<n;ht[rk[i++]]=k)
        37     for(k?k--:0,j=sa[rk[i]-1];rk[i]&&s[i+k]==s[j+k];k++);
        38 }/////
        39 void rmq(){
        40     lg[1]=0;for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
        41     for(int i=0;i<=n;i++) f[i][0]=ht[i];
        42     for(int i=1;i<17;i++)
        43     for(int j=0;j+(1<<i)<=n;j++)
        44     f[j][i]=min(f[j][i-1],f[j+(1<<i-1)][i-1]);
        45 }////
        46 int lcp(int x,int y){
        47     if(x==y)return n-x;////
        48     x=rk[x],y=rk[y]; 
        49     if(x>y) swap(x,y);
        50     int t=lg[y-x];
        51     int tmp;
        52     tmp=min(f[x+1][t],f[y-(1<<t)+1][t]);///
        53 //    printf("%d %d %d
        ",x,y,tmp);
        54     return tmp;
        55 }/////
        56 int l,r,len;
        57 void find(ll k){
        58     int i;
        59     for(i=1;i<=n;k-=b[i++])////
        60     if(b[i]>=k){l=sa[i],r=sa[i]+ht[i]+k-1;len=r-l+1;break;}///
        61     //printf("%d
        ",i);
        62 }/////
        63 bool ask(int L,int R){
        64     int Len=R-L+1;
        65     int t=min(min(len,Len),lcp(l,L));
        66     if(t==Len&&t<=len) return 1;
        67     if(t==len) return 0;
        68     return s[l+t]>s[L+t];////
        69 }////
        70 bool check(){
        71     int i,j,cnt=0;
        72     for(i=j=n-1;~i;i=j,cnt++){
        73         while(~j&&ask(j,i))j--;
        74         if(j==i||cnt>k)return 0;
        75       //    printf("%d
        ",j);
        76     }
        77 //    printf("
        ");
        78     return cnt<=k;
        79 }/////
        80 int main()
        81 {    //freopen("bzoj4310.in","r",stdin);
        82     //freopen("bzoj4310.out","w",stdout);
        83     scanf("%d",&k);
        84     scanf("%s",s); n=strlen(s); s[n++]=0;
        85     build_sa(); build_ht(); rmq();//
        86     ll L=1,R=0,mid;  n--;
        87     for(int i=1;i<=n;i++) R+=(b[i]=n-sa[i]-ht[i]);///
        88     while(L<=R){ 
        89         find(mid=L+R>>1);
        90         if(check())ansl=l,ansr=r,R=mid-1;else L=mid+1;//
        91     }
        92     for(int i=ansl;i<=ansr;i++)putchar(s[i]);//
        93     return 0;
        94 }//by tkys_Austin;
        bzoj4310
  • 相关阅读:
    table表框去掉相邻的间隔
    各种日期格式化返回
    校验金额、大小写字母、大写字母、合法uri、email
    vue js校验金钱、数字
    vue-router 动态添加 路由
    可视化-echarts流向图制作
    HTTP状态码
    二分查找
    编程语言的变量为啥不能是数字开头
    python位运算
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10222697.html
Copyright © 2020-2023  润新知