• [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;
    }
    
  • 相关阅读:
    SQL Server和Oracle数据库索引介绍
    ITPUB上一个Oracle面试题
    国服《巫妖王之怒》3.35冰双持新手献礼指南
    WLK奥法输出循环
    flume架构初接触
    密码校验正则表达式(java 环境)
    初学Mahout测试kmeans算法
    身份证校验(java)
    gcc 中 O选项对空函数的优化
    《肖申克的救赎》语录
  • 原文地址:https://www.cnblogs.com/asuldb/p/10641604.html
Copyright © 2020-2023  润新知