专项测试-字符串2


T1 肃正协议

题意:一个区间是上一个区间的真子串且区间不相交,求最大区间数

设f[i]表示以i作为第一个串的第一项,答案的最大值

满足

  1. f[i]<=f[i+1]+1
  2. 答案的范围不超过\(O(\sqrt n)\)

就可以从后往前推,f[i]从f[i+1]+1递减判断是否合法

判断时可以将真子串这个限制进一步缩小

一个区间(i,j)是另一个区间(a,b)的真子串,那么一定存在\(a'\in[a,b],b'\in[a,b],且a',使得(i,j)是(a',b')的真子串,且len(a',b')=len(i,j)+1,这样的区间显然潜力更大

于是一个长度len,f[i]=len合法仅当s[i,i+len-2],s[i+1,i+len-1]在i+len-1之后已经成为了合法起始串

unordered_map动态维护合法起始串,在len--时顺便将以i+len-1为起点的合法起始串加进unordered_map

复杂度\(O(n\sqrt n)\)

代码
#include
using namespace std;
#define ull long long
const int N=5e5+11;
const ull p=9973;
char tx[N];
int n;
int f[N];
ull hs[N],mi[N]={1};
unordered_map mp;
inline int max_(int x,int y){return x>y?x:y;}
int main()
{
	scanf("%s",tx+1);
	n=strlen(tx+1);
	for(int i=1;i<=n;++i) mi[i]=mi[i-1]*p,hs[i]=hs[i-1]*p+tx[i]-'a'+1;
	int ans=0;
	ull hs1;
	for(int len,st,i=n;i;--i)
	{
		f[i]=1;
		st=f[i+1]+1;
		while(st)
		{
			if(st==1) break;
			if(mp.find(hs[i+st-2]-hs[i-1]*mi[st-1])!=mp.end()||mp.find(hs[i+st-1]-hs[i]*mi[st-1])!=mp.end()){f[i]=st;break;}
			--st;
			len=f[i+st];
			while(len)
			{
				hs1=hs[i+st+len-1]-hs[i+st-1]*mi[len];
				if(mp.find(hs1)!=mp.end()) break;
				mp[hs1]=1;
				--len;
			}
		}
		ans=max_(ans,f[i]);
	}
	cout<

T2 虚空恶魔

题意:一个区间是另一个区间的子串且不相交,求max(len1* len2)

可以先考虑两个相同且长度为len的串[i,j],[a,b],i<=j

对于所有和[i,j]本质相同的串,对答案贡献最大的一对满足一个j最小,另一个a最大,也就是取两边的

sam上每个节点维护最小和最大的endpos就行了

代码
#include
using namespace std;
#define ll long long
const int N=4e6+11;
char tx[N];
int n,tot=1,last=1;
int len[N];
int link[N];
int a[N],c[N];
int mn[N],mx[N];
int tran[N][27];
unordered_map::iterator it;
inline ll max_(ll x,ll y){return x>y?x:y;}
inline int min_(int x,int y){return x>y?y:x;}
void insert(int i)
{
	int w=tx[i]-'a'+1,x=++tot,p=last;
	len[x]=len[p]+1;
	for(;p&&!tran[p][w];p=link[p]) tran[p][w]=x;
	mx[x]=mn[x]=i;
	if(!p) link[x]=1;
	else
	{
		int q=tran[p][w];
		if(len[q]==len[p]+1) link[x]=q;
		else
		{
			int clone=++tot;
			len[clone]=len[p]+1;
			memcpy(tran[clone],tran[q],sizeof(tran[q]));
			link[clone]=link[q];
			link[x]=link[q]=clone;
			for(;p&&tran[p][w]==q;p=link[p]) tran[p][w]=clone;
			mx[clone]=mn[clone]=mn[q];
		}
	}
	last=x;
	return;
}
int main()
{
	cin>>(tx+1);
	n=strlen(tx+1);
	for(int i=1;i<=n;++i) insert(i);
	for(int i=1;i<=tot;++i) ++c[len[i]];
	for(int i=1;i<=n;++i) c[i]+=c[i-1];
	for(int i=1;i<=tot;++i) a[c[len[i]]--]=i;

	for(int i=tot;i;--i) mx[link[a[i]]]=max_(mx[link[a[i]]],mx[a[i]]);
	ll ans=0;
	for(int ed,i=2;i<=tot;++i)
		if(mx[i])
		{
			ed=min_(len[i],mx[i]-mn[i]);
			ans=max_(ans,1ll*ed*(n-mn[i]));
			ans=max_(ans,1ll*ed*(mx[i]-ed));
		}
	cout<

T3 高维入侵

没看懂题解,待补