• bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】


    把模板串建一个广义SAM
    然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串
    二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i-1],f[j]+i-j(i-a[i]<=j<=i-L)},根据性质,i-a[i]是单调的(或者直接看a[i]的预处理过程也能看出来),所以这个dp可以用单调队列优化转移,最后判断是否f[n]>=L*0.9

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=3000005;
    int n,m,fa[N],ch[N][2],dis[N],cur=1,con=1,la,a[N],q[N],f[N];
    char s[N];
    void ins(int c,int id)
    {
    	la=cur,dis[cur=++con]=id;
    	int p=la;
    	for(;p&&!ch[p][c];p=fa[p])
    		ch[p][c]=cur;
    	if(!p)
    		fa[cur]=1;
    	else
    	{
    		int q=ch[p][c];
    		if(dis[q]==dis[p]+1)
    			fa[cur]=q;
    		else
    		{
    			int nq=++con;
    			dis[nq]=dis[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    			fa[nq]=fa[q];
    			fa[q]=fa[cur]=nq;
    			for(;ch[p][c]==q;p=fa[p])
    				ch[p][c]=nq;
    		}
    	}
    }
    bool ok(int w,int n)
    {
    	int l=1,r=0;//cerr<<w<<endl;
    	for(int i=1;i<=n;i++)
    	{
    		f[i]=f[i-1];
    		while(l<=r&&q[l]<i-a[i])
    			l++;
    		if(l<=r)
    			f[i]=max(f[i],f[q[l]]+i-q[l]);
    		if(i-w+1>=0)
    		{
    			while(l<=r&&f[q[r]]-q[r]<=f[i-w+1]-(i-w+1))
    				r--;
    			q[++r]=i-w+1;
    		}//cerr<<i<<" "<<f[i]<<endl;
    	}
    	return f[n]*10>=n*9;
    }
    int main()
    {
    	scanf("%d%d",&m,&n);
    	for(int j=1;j<=n;j++)
    	{
    		scanf("%s",s+1);
    		cur=1;
    		for(int i=1,len=strlen(s+1);i<=len;i++)
    			ins(s[i]-'0',i);
    	}
    	while(m--)
    	{
    		scanf("%s",s+1);
    		int len=strlen(s+1);
    		for(int i=1,l=0,p=1;i<=len;i++)
    		{
    			int c=s[i]-'0';
    			if(ch[p][c])
    				l++,p=ch[p][c];
    			else
    			{
    				for(;p&&!ch[p][c];p=fa[p]);
    				if(!p)
    					l=0,p=1;
    				else
    					l=dis[p]+1,p=ch[p][c];
    			}
    			a[i]=l;//cerr<<i<<" "<<a[i]<<endl;
    		}
    		int l=0,r=len,ans=0;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(ok(mid,len))
    				l=mid+1,ans=mid;
    			else
    				r=mid-1;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用RoboCopy 命令[转载]
    取得超级管理员权限
    重置网络命令win7
    ASP.NET Global.asax详解【转】
    逆波兰式算法
    设计模式【转自JackFrost的博客】
    VS2013 F12无法转到函数的定义处,总是从“元数据”获取的问题 ——解决方法
    扩展方法 C#
    委托Func和Action【转】
    添加路由
  • 原文地址:https://www.cnblogs.com/lokiii/p/10009223.html
Copyright © 2020-2023  润新知