CTSC2012 熟悉的文章

Description

link

给定一些模板串和一些询问,每个询问以字符串的形式给出

对于每个询问给出的字符串,可以将其进行分割,使得其子串是某个模板串的子串

同时有一个标量 (p) 为分割方案中最小的 子串 的长度

求所有方案中的 (p_{max})

Solution

求子串的方法就是后缀自动机,然后这题先对所有模板串建广义 (sam)

这个 (p) 是可以二分的,然后把问题转成判定性问题

(f_i) 为当前询问前 (i) 个字符能匹配的最大长度,然后有

[f_i=max( maxlimits_{j=i-match_i}^{i-p}f_j+i-j,f_{i-1}) ]

其中 (match_i) 是当前字符在广义 (sam) 的最长匹配长度

可以把询问放到上面跑一下求出来

如果最后 (f_lge p imes0.9) 就表示当下的 (p) 满足

然后我们发现这个方程并不能满足我们的时间需求

看看式子,有种斜率优化的冲动

打个表发现两边都满足不降……

(这里证明?看看nofind的博客吧)

然后直接单调队列优化这个过程即可

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1.1e6+10; 
	int fa[N<<1],ch[N<<1][2],len[N<<1],tot=1,las=1,n,m;
	inline void copy(int x,int y)
	{
		for(int i=0;i<2;++i) ch[x][i]=ch[y][i];
		return ;
	}
	inline void extend(int x)
	{
		int tmp=las,np=las=++tot; len[np]=len[tmp]+1;
		while(tmp&&!ch[tmp][x]) ch[tmp][x]=np,tmp=fa[tmp];
		if(!tmp) return fa[np]=1,void();
		int q=ch[tmp][x]; 
		if(len[q]==len[tmp]+1) return fa[np]=q,void();
		int clone=++tot; fa[clone]=fa[q]; fa[q]=fa[np]=clone; copy(clone,q);
		len[clone]=len[tmp]+1;
		while(tmp&&ch[tmp][x]==q) ch[tmp][x]=clone,tmp=fa[tmp]; 
		return ;
	}
	char s[N];
	int maxx[N],q[N],h,t,l,f[N],T;
	inline void prework()
	{
		int res=0,now=1; l=strlen(s+1);
		for(int i=1;i<=l;++i)
		{
			int t=s[i]-'0';
			while(now&&!ch[now][t]) now=fa[now],res=len[now];
			if(now) now=ch[now][t],res++;
			else now=1,res=0; 
			maxx[i]=res;
		} return ;
	}
	inline bool check(int x)
	{
		h=1; t=0; q[1]=0; 
		for(int i=1;i<x;++i) f[i]=0;
		for(int i=x;i<=l;++i) 
		{
			f[i]=f[i-1];
			while(h<=t&&f[q[t]]-q[t]<f[i-x]-i+x) --t;
			q[++t]=i-x; 
			while(h<=t&&q[h]<i-maxx[i]) ++h;
			if(h<=t) f[i]=max(f[i],f[q[h]]+i-q[h]);
		}
		
		return f[l]*10>=l*9;
	}
	signed main()
	{
		T=read(); m=read();
		for(int i=1,tl;i<=m;++i) 
		{
			scanf("%s",s+1); tl=strlen(s+1); las=1; 
			for(int j=1;j<=tl;++j) extend(s[j]-'0');
			
		} 
		while(T--)
		{
			scanf("%s",s+1); prework();
			
			int l=1,r=strlen(s+1),ans=0;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(check(mid)) ans=mid,l=mid+1;
				else r=mid-1;
			}printf("%lld
",ans);
		}
		return 0;
	}
}
signed main(){return yspm::main();} 
原文地址:https://www.cnblogs.com/yspm/p/13289710.html