• BZOJ 2806 【CTSC2012】 Cheat


    题目链接:Cheat

      话说这道题很久以前某人就给我们考过,直到现在,我终于把这个坑填上了……

      这道题要我们把一个串(S)划分成若干块,每块长度不小于(L_0),使得能够在文章库中完全匹配的块的长度和占总长度的(90\%)以上。首先,答案显然是可以二分的。于是,我们就可以二分一个答案(ans),考虑如何(check)。

      很显然的一个想法就是(dp)。如果我们知道这个串的第(i)位往前最多能够走(x_i)位,使得(S_{i-x_i})到(S_i)组成的串能够在文章库中匹配,那么我们就可以写出(dp)方程了:egin{aligned} f_i=&max { f_j+i-j }(i-x_i le j le i-ans) \ = &i+max { f_i-j } (i-x_i le j le i-ans) end{aligned}

      当然,(f_i=max(f_i,f_{i-1}))

      然后,我们就可以发现(i-x_i)是单调的(话说我刚开始还没有看出来),然后由于(i-ans)显然也是单调的,所以我们就可以弄个单调队列维护区间最大值即可。最后再判断一下总的匹配长度是否大于等于总长度的(90\%)即可。

      下面贴代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define maxn 2200010
    
    using namespace std;
    typedef long long llg;
    
    int n,m,tot,last,f[maxn>>1],L,pi[maxn>>1];
    int son[maxn][2],fa[maxn],len[maxn],d[maxn>>1],ld,rd;
    char s[maxn>>1];
    
    void add(int p,int x){
    	int np=++tot; len[np]=len[p]+1,fa[np]=p; last=np;
    	for(;p && !son[p][x];p=fa[p]) son[p][x]=np;
    	if(!p) fa[np]=1;
    	else{
    		int q=son[p][x];
    		if(len[q]==len[p]+1) fa[np]=q;
    		else{
    			int nq=++tot;
    			memcpy(son[nq],son[q],sizeof(son[q]));
    			fa[nq]=fa[q]; fa[q]=fa[np]=nq; len[nq]=len[p]+1;
    			for(;son[p][x]==q;p=fa[p]) son[p][x]=nq;
    		}
    	}
    }
    
    bool check(int x){
    	ld=rd=0;
    	for(int i=1;i<=L;i++){f[i]=f[i-1];
    		if(i>=x){
    			while(ld<rd && f[d[rd-1]]-d[rd-1]<=f[i-x]-i+x) rd--;
    			d[rd++]=i-x;
    		}
    		while(ld<rd && d[ld]<i-pi[i]) ld++;
    		if(ld<rd) f[i]=max(f[i],f[d[ld]]-d[ld]+i);
    	}
    	return f[L]*10>=9*L;
    }
    
    int main(){
    	File("a");
    	scanf("%d %d",&n,&m); tot=1;
    	for(int i=1,l;i<=m;i++){
    		scanf("%s",s+1);
    		last=1; l=strlen(s+1);
    		for(int j=1;j<=l;j++) add(last,s[j]-'0');
    	}
    	for(int i=1,l,r,mid;i<=n;i++){
    		scanf("%s",s+1);
    		l=0; L=r=strlen(s+1);
    		for(int j=1,p=1,le=0;j<=L;j++){
    			while(p!=1 && !son[p][s[j]-'0']) p=fa[p],le=len[p];
    			if(son[p][s[j]-'0']) p=son[p][s[j]-'0'],le++; pi[j]=le;
    		}
    		while(l!=r){
    			mid=(l+r+1)>>1;
    			if(check(mid)) l=mid;
    			else r=mid-1;
    		}
    		printf("%d
    ",l);
    	}
    	return 0;
    }
    
  • 相关阅读:
    c# 如何获取当前方法的调用堆栈(转载)
    被忽视的问题:测试环境配置管理
    性能测试如何创造业务价值
    高级性能测试工程师面试必问十大问题
    Vue随机验证码组件
    面试突击61:说一下MySQL事务隔离级别?
    面试突击60:什么情况会导致 MySQL 索引失效?
    抽奖动画 鲤鱼跳龙门
    VScode 安装PHPdebug新版Xdebug3.0
    Java 项目安全、如何进行安全审计
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6343349.html
Copyright © 2020-2023  润新知