zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6343349.html
Copyright © 2011-2022 走看看