码迷,mamicode.com
首页 > 其他好文 > 详细

[ZJOI2013]丽洁体

时间:2019-04-02 12:27:03      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:str   hash   unsigned   getch   结束   \n   前缀   做了   字符   

题目

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

发现一个非常显然的事情,因为我们要的是\(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\n",tot+h);
    return 0;
}

[ZJOI2013]丽洁体

标签:str   hash   unsigned   getch   结束   \n   前缀   做了   字符   

原文地址:https://www.cnblogs.com/asuldb/p/10641604.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!