zoukankan      html  css  js  c++  java
  • BZOJ 2806: [Ctsc2012]Cheat(单调队列优化dp+后缀自动机)

    传送门

    解题思路

      肯定先要建出来广义后缀自动机。刚开始以为是个二分+贪心,写了一下结果(20)分。说一下正解,首先显然(L_0)具有单调性,是可以二分的。考虑二分后怎样判合法,对于分割序列很容易想到(dp),设(f_i)表示前(i)个字符匹配成功数量,那么有转移方程(f_i=max(f_j+i-j)(i-j>=L)(j)(i)可以匹配 ())(L)是二分出来的限制,判断是否能匹配可以预处理,预处理出(mth_i)表示(i)最多能与往前(mth_i)位匹配成功,那么第二个条件就变成了(j>=i-mth_i)。如果这样做是(O(n^2logn))的,实测可以拿到(75)分2333。考虑优化,发现(i-mth_i)具有单调性,因为每移动一格(i)(+1),而(mth_i)最多(+1)。那么可以用一个单调递减队列来优化,每次将(i-lim)入队,取出队头更新答案,时间复杂度为(O(nlogn))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    
    using namespace std;
    const int N=1100005<<1;
    
    int n,m,res,ans,f[N],mth[N],q[N],hd,tl;
    char s[N];
    
    struct SAM{
    	int ch[N][2],fa[N],l[N],lst,cnt;
    	void Insert(int c){
    		int p=lst,np=++cnt; l[np]=l[p]+1; lst=cnt;
    		for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    		if(!p) fa[np]=1;
    		else {
    			int q=ch[p][c]; 
    			if(l[p]+1==l[q]) fa[np]=q;
    			else {
    				int nq=++cnt; l[nq]=l[p]+1;
    				memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    				fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    				for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    			}
    		}
    	}
    	void prework(int len){
    		int now=1,num=0;
    		for(int i=1;i<=len;i++){
    			if(ch[now][s[i]-'0']) now=ch[now][s[i]-'0'],num++;
    			else {
    				for(;now && !ch[now][s[i]-'0'];now=fa[now]);
    				if(!now) now=1,num=0;
    				else num=l[now]+1,now=ch[now][s[i]-'0'];
    			}
    			mth[i]=num;
    		}
    	}
    	bool check(int lim,int len){	
    		int tmp; hd=1; tl=0; 
    		for(int i=1;i<=len;i++){
    			f[i]=f[i-1]; if(i<lim) continue; tmp=i-mth[i];
    			while(hd<=tl && f[q[tl]]-q[tl]<=f[i-lim]-i+lim) tl--;
    			q[++tl]=i-lim;
    			while(hd<=tl && q[hd]<tmp) hd++;
    			if(hd<=tl) f[i]=max(f[i],f[q[hd]]-q[hd]+i);
    		}
    //		for(int i=1;i<=len;i++){
    //			f[i]=f[i-1];
    //			for(int j=max(0,i-mth[i]);j+lim<=i;j++)
    //				f[i]=max(f[i],f[j]+i-j);
    //		}
    		return len-f[len]>res?0:1;
    	}
    	void solve(int len){	
    		prework(len);
    		int L=1,R=len,mid;
    		while(L<=R){
    			mid=(L+R)>>1;
    			if(check(mid,len)) L=mid+1,ans=mid;
    			else R=mid-1;
    		}
    		printf("%d
    ",ans);
    	}
    }sam;
    
    int main(){
    	scanf("%d%d",&n,&m); sam.cnt=1; int len;
    	for(int i=1;i<=m;i++){
    		scanf("%s",s+1); sam.lst=1;
    		len=strlen(s+1);
    		for(int j=1;j<=len;j++) sam.Insert(s[j]-'0');
    	}
    	for(int i=1;i<=n;i++){
    		scanf("%s",s+1); len=strlen(s+1);
    		res=(len*9+9)/10; res=len-res;
    		sam.solve(len); ans=0;
    	}
    	return 0;
    }	
    
  • 相关阅读:
    0diff算法参考资料
    js 对象属性值
    一些带有设计模式的优秀代码
    vue 配置多页面
    cms 管理系统
    网络技术:EtherChannel 链路汇聚
    网络技术:VLAN 中继协议(VTP)
    网络管理:管理信息库
    网络管理:抽象语法表示 ASN.1
    网络管理:基本编码规则(BER)
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10457823.html
Copyright © 2011-2022 走看看