[ZJOI2013]丽洁体

题目

还以为是序列自动机真是吓人

发现一个非常显然的事情,因为我们要的是(A...B...C)(A)一定要成为前缀,(C)一定要成为后缀,于是我们发现我们需要让(A)尽量靠前(C)尽量靠后

一是因为这样(A)(C)去掉的位置尽量少,二来能留给(B)更多的空间

这里直接贪心就好了,先选择(A)第一个位置尽量靠前的,在选择第二个位置中,小于上一个选择的尽量靠前的,这样一直做下去就好了

之后搞(B),我们发现这里我们的贪心失效了,因为我们的贪心只能保证出现位置尽量靠前,而不能保证开始位置和结束位置相差最小

但是我们发现保证每一种字符串出现次数不超过(500),那不就随便做了吗

我们枚举(B)的第一个字符在(T)里出现的所有位置,之后贪心找到这个位置对应的最靠前的位置

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define re register
#define LL long long
#define ull unsigned long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=50005;
char S[15];
ull base=233;
int n,a,b,c,sz,lp,rp,tot;
std::vector<int> v[maxn];
int pos[maxn];
ull d[maxn],A[maxn],T[maxn],B[maxn],C[maxn];
inline ull getHash() {
    ull now=0;
    int len=strlen(S);
    for(re int i=0;i<len;i++) now=now*base+S[i];
    return now;
}
inline void init(){
    do{scanf("%s",S);T[++n]=getHash();}while(getchar()==' ');
    do{scanf("%s",S);A[++a]=getHash();}while(getchar()==' ');
    do{scanf("%s",S);B[++b]=getHash();}while(getchar()==' ');
    do{scanf("%s",S);C[++c]=getHash();}while(getchar()==' ');
}
inline int find(ull x) {
    int l=1,r=sz;
    while(l<=r) {
        int mid=l+r>>1;
        if(d[mid]==x) return mid;
        if(d[mid]<x) l=mid+1;
            else r=mid-1;
    }
    return 0;
}
int main() {
    init();
    for(re int i=1;i<=n;i++) d[i]=T[i];
    std::sort(d+1,d+n+1);
    sz=std::unique(d+1,d+n+1)-d-1;
    for(re int i=1;i<=n;i++) {
        int x=find(T[i]);
        v[x].push_back(i);
    }
    lp=0;
    for(re int i=1;i<=a;i++) {
        int x=find(A[i]);
        int l=0,r=v[x].size()-1,ans=0;
        while(l<=r) {
            int mid=l+r>>1;
            if(v[x][mid]>lp) ans=mid,r=mid-1;
                else l=mid+1;
        }
        lp=v[x][ans];
    }
    rp=n+1;
    for(re int i=c;i;--i) {
        int x=find(C[i]);
        int l=0,r=v[x].size()-1,ans=0;
        while(l<=r) {
            int mid=l+r>>1;
            if(v[x][mid]<rp) ans=mid,l=mid+1;
                else r=mid-1;
        }
        rp=v[x][ans];
    }
    for(re int i=1;i<=sz;i++) v[i].clear();
    for(re int i=lp+1;i<rp;i++) {
        int x=find(T[i]);
        v[x].push_back(i);
    }
    tot=lp-a+(n-rp+1-c);
    for(re int i=1;i<=b;i++) pos[i]=find(B[i]);
    int h=n;
    for(re int i=0;i<v[pos[1]].size();i++) {
        int now=v[pos[1]][i];
        for(re int j=2;j<=b;j++) {
            int x=pos[j];
            int l=0,r=v[x].size()-1,ans=-1;
            while(l<=r) {
                int mid=l+r>>1;
                if(v[x][mid]>now) ans=mid,r=mid-1;
                    else l=mid+1;
            }
            if(ans==-1) {now=2*n;break;}
            now=v[x][ans];
        }
        h=min(h,now-v[pos[1]][i]+1-b);
    }
    printf("%d
",tot+h);
    return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/10641604.html