Locker Room Gym

题意:

在长度为 N 的主串中选取一个长度为 K 的子串可以把原主串全覆盖。覆盖的条件是 选取的子串 s 把原串中所有长度为 K 并且字典序小于 s 的子串的字符标记之后(每个字符可被标记多次),

如果原串的全部字符都被标记,则当前选取的子串 s 可以覆盖这个主串。

求字典序最小的 s 。原串是一个环!!!即最小化最大值。

思路:后缀数组,直接开2倍长度跑SA就好了,因为我们要找一个满足能标记完n个字符的排名最小的长度为k的子串,所以我们可以二分排名check一下长度是否大于等于n就好了。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
//#define _for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
double eps=0.05;
ll mod=1e9+7;
const int INF=0x3f3f3f3f,inf =0x3f3f3f3f;
const int MAXN=2e3+10;
const int maxn = 1e7+10;
//ll inf=100000000000000;
//template<typename T>inline void read(T &x)
//{
//    x=0;
//    static int p;p=1;
//    static char c;c=getchar();
//    while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
//    while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
//   x*=p;
//}
typedef unsigned long long ull;
const int N=2e6+7;
const double PI=acos(-1.0);
char ss[N];
int s[N];
int sa[N],t[N],t2[N],c[N];//y[N];
int rk[N],H[N];
void build_sa(int n,int m){
    int i,*x=t,*y=t2;
    for( i=0;i<m;i++)c[i]=0;
    for( i=0;i<n;i++)c[x[i]=s[i]]++;
    for( i=1;i<m;i++)c[i]+=c[i-1];
    for( i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(i=n-k;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=0;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
void getH(int n){
    int i,j,k=0;
    for(i=0;i<n;i++)rk[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        H[rk[i]]=k;
    }
}
//void SA(int n,int m){
//    for(int i=0;i<m;i++) c[i]=0;
//    for(int i=0;i<n;i++) c[rk[i]=s[i]]++;
//    for(int i=1;i<m;i++) c[i]+=c[i-1];
//    for(int i=n-1;i>=0;i--) sa[--c[rk[i]]]=i;
//    for(int k=1;k<=n;k<<=1){
//        int num=0;
//        for(int i=n-k;i<n;i++) y[num++]=i;
//        for(int i=0;i<n;i++) if(sa[i]>=k) y[num++]=sa[i]-k;
//        for(int i=0;i<m;i++) c[i]=0;
//        for(int i=0;i<n;i++) c[rk[i]]++;
//        for(int i=1;i<m;i++) c[i]+=c[i-1];
//        for(int i=n-1;i>=0;i--)
//            sa[--c[rk[y[i]]]]=y[i];
//        swap(rk,y);
//        rk[sa[0]]=0; num=1;
//        for(int i=1;i<n;i++)
//            rk[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? num-1:num++);
//        if(num>=n) break;
//        m=num;
//    }
//}
//void HH (int n){
//    for(int i=1;i<=n;i++) sa[rk[i]]=i;
//    for(int i=0,k=0;i<n;i++){
//        if(k) k--; else k=0;
//        int j=sa[rk[i]-1];
//        while(s[i+k]==s[j+k]) k++;
//        H[rk[i]]=k;
//    }
//}
bool check(int mid,int n,int k){
    int st=0,en=-1;
    for(int i=0;i<n;i++){
        if(rk[i]>mid) continue;
        if(en<i) st=i;
        en=i+k;
        if(en-st>=n) return true;
    }
    return false;
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    scanf("%s",ss);
    for(int i=0;i<n;i++)ss[n+i]=ss[i];
    for(int i=0;i<2*n;i++)s[i]=ss[i]-'a'+1;
    n<<=1;
    s[n]=0;
//    for(int i=0;i<n;i++)printf("%d",s[i]);
//    cout<<endl;
    build_sa(n+1,30);
    //SA(n+1,30);
    getH(n+1);
    //HH(n);
//    for(int i=0;i<n;i++){
//        printf("%d ",sa[i]);
//    }
//    cout<<endl;
//    for(int i=0;i<n;i++){
//        printf("%d ",rk[i]);
//    }
//    cout<<endl;
    int l=0,r=n,ans;
    while(l<=r){
        int mid = (l+r)>>1;
        if(check(mid,n,k)) r=mid-1,ans=mid;
        else l=mid+1;
    }
    for(int i=0;i<n;i++){
        if(rk[i]==ans){
            for(int j=i;j<i+k;j++)
                printf("%c",ss[j]);
            return 0;
        }
    }
//    int l=0,r=n,ans;
//    while(l<=r){
//        int mid=(l+r)>>1;
//        if(check(mid,n,k))r=mid-1,ans=mid;
//        else l=mid+1;
//    }
//    cout<<ans<<endl;
//    cout<<ss<<endl;
//    for(int i=0;i<n;i++){
//        if(rk[i]==ans){
//                cout<<i<<" "<<i+k<<endl;
//            for(int j=i;j<i+k;j++){
//                printf("%c",ss[j]);
//            }
//            return 0;
//        }
    //}
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/kayiko/p/13618446.html