CF1043G Speckled Band

一、题目

点此看题

二、解法

我直接翻译官方题解了

你发现答案的情况很有限,要么是无解,要么是 \([1,4]\) 中的某一个。

如果没有一个字符出现次数超过一次就无解,根据抽屉原理判断 \(l\) 的前 \(27\) 个字符即可。

如果答案是 \(1\),设 \(A\) 为某个字符串,原串一定能被 \(AA...A\),那么枚举 \(r-l+1\) 的质因子作为 \(A\) 的长度 \(p\),然后看是否满足 \(lcp(l,l+p)\geq r-l+1-p\) 即可。

如果答案是 \(2\),那么有这些情况:aba,aab,baa,第二三种情况因为设计 \(aa\) 串的统计,可以用优秀的拆分的方法,求出 \(lt_i\) 表示满足 \(s[i,x)\) 是一个 \(aa\) 串最小的 \(x\)\(rt_i\) 表示满足 \(s(x,i]\) 是一个 \(aa\) 串的最大的 \(x\),那么如果 \(lt_l\leq r\or rt_r\geq l\) 就说明合法。第一种情况等价于判断子串 \([l,r]\) 是否存在 \(border\),这是最有趣的问题,我们放在最后解决。

如果答案是 \(3\),那么有这些情况:abac,baca,baac,第一二种情况 \(a\) 串的长度是 \(1\) 最优,所以我们只需要判断 \(s_l\or s_r\) 在这个区间出现过没有,第三种情况等价于判断是否存在 \(l\leq i\leq r\) 使得 \(lt_i\leq r\),用 \(st\) 表维护一下就行了。

现在我们来解决最有趣的问题吧,有一种神奇的方法是我们先看是否存在长度 \(<\sqrt n\)\(border\),直接用 \(hash\) 来验证即可。如果现在还没有检测出 \(border\) 那么 \(border\) 的长度 \(>\sqrt n\),我们验证后缀 \(l\) 排名相邻的 \(\sqrt n\) 个后缀中有没有满足条件的。

证明我还要多想一下

如果前面的都不是那么答案就是 \(4\) 了,时间复杂度 \(O(n\sqrt n)\),常数很大。

#pragma GCC optimize(2)
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
const int M = 200005;
#define ull unsigned long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,q,S,cnt;char s[M];
//init for AA
int lt[M],rt[M],lg[M],fa[M][2],dp[M][20],pre[M][26];
ull hs[M],pw[M];
ull get(int l,int r)
{
	if(l<1 || r>n) return rand()*rand();//meaningless
	return hs[r]-hs[l-1]*pw[r-l+1];
}
int find(int t,int x)
{
	if(x!=fa[x][t]) fa[x][t]=find(t,fa[x][t]);
	return fa[x][t];
}
int ask(int l,int r)
{
	int k=lg[r-l+1];
	return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
void init1()
{
	pw[0]=1;fa[n+1][0]=fa[n+1][1]=n+1;
	for(int i=1;i<=n;i++)//the prefix sum of appearence
	{
		for(int j=0;j<26;j++)
			pre[i][j]=pre[i-1][j];
		pre[i][s[i]-'a']++;
	}
	for(int i=1;i<=n;i++)
	{
		lt[i]=n+1;rt[i]=0;
		hs[i]=371*hs[i-1]+s[i];
		pw[i]=pw[i-1]*371;
		fa[i][0]=fa[i][1]=i;
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i+k<=n;i+=k)
		{
			int j=i+k,lcp=0,lcs=0,l=1,r=k;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(get(i-mid+1,i)==get(j-mid+1,j))
					lcs=mid,l=mid+1;
				else r=mid-1;
			}
			l=1;r=k;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(get(i,i+mid-1)==get(j,j+mid-1))
					lcp=mid,l=mid+1;
				else r=mid-1; 
			}
			if(lcs+lcp<k) continue;
			l=max(1,i-lcs+1);r=min(i+lcp-k,n);
			for(int i=find(0,l);i<=r;i=find(0,i))
			{
				lt[i]=i+2*k;
				fa[i][0]=find(0,i+1);i++;
				cnt++;
			}
			l=max(1,j+k-lcs);r=min(j+lcp-1,n);
			for(int i=find(1,l);i<=r;i=find(1,i))
			{
				rt[i]=i-2*k;
				fa[i][1]=find(1,i+1);i++;
				cnt++;
			}
		}
	for(int i=1;i<=n;i++)
	{
		dp[i][0]=lt[i];
		if(i>1) lg[i]=lg[i>>1]+1;
	}
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}
//init for suffix array
int x[M],y[M],c[M],sa[M],rk[M],hi[M][20];
void init2()
{
	int m=200;
	for(int i=1;i<=n;i++) ++c[x[i]=s[i]];
	for(int i=1;i<=m;i++) c[i]+=c[i-1];
	for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
	for(int k=1;k<=n;k<<=1)
	{
		int num=0;
		for(int i=n-k+1;i<=n;i++) y[++num]=i;
		for(int i=1;i<=n;i++)
			if(sa[i]>k) y[++num]=sa[i]-k;
		for(int i=1;i<=m;i++) c[i]=0;
		for(int i=1;i<=n;i++) ++c[x[i]];
		for(int i=1;i<=m;i++) c[i]+=c[i-1];
		for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i];//mistake
		swap(x,y);
		x[sa[1]]=num=1;
		for(int i=2;i<=n;i++)
			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]
			&& y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
		if(m==n) break;
		m=num;
	}
	int k=0;
	for(int i=1;i<=n;i++) rk[sa[i]]=i;
	for(int i=1;i<=n;i++)
	{
		if(rk[i]==1) continue;
		if(k) k--;
		int j=sa[rk[i]-1];
		while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) k++;
		hi[rk[i]][0]=k;
	}
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			hi[i][j]=min(hi[i][j-1],hi[i+(1<<j-1)][j-1]);
}
int lcp(int l,int r)
{
	l=rk[l];r=rk[r];
	if(l>r) swap(l,r);l++;
	int k=lg[r-l+1];
	return min(hi[l][k],hi[r-(1<<k)+1][k]);
}
int s0(int l,int r)
{
	int t[26]={};
	for(int i=l;i<=min(l+27,r);i++) t[s[i]-'a']++;
	for(int i=0;i<26;i++) if(t[i]>1) return 0;
	return 1;
}
int s1(int l,int r)
{
	int x=r-l+1,y=x;
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			while(x%i==0) x/=i;
			if(lcp(l,l+y/i)>=y-y/i) return 1;
		}
	}
	if(x!=1)  return lcp(l,l+y/x)>=y-y/x;
	return 0;
}
int s2(int l,int r)
{
	//aab,baa
	if(lt[l]<=r || rt[r]>=l) return 1;
	//aba
	for(int i=1;i<=min(S,r-l);i++)
		if(get(l,l+i-1)==get(r-i+1,r))
			return 1;//check the border within sqrt(n)
	int p=rk[l];
	for(int t=max(1,p-S);t<=min(n,p+S);t++)
	{
		int i=sa[t];
		if(l<i && i<=r && lcp(l,i)>=r-i+1)
			return 1;//using suffix array
	}
	return 0;
}
int s3(int l,int r)
{
	//abac
	if(pre[r][s[l]-'a']-pre[l][s[l]-'a']>0) return 1;
	//baca
	if(pre[r-1][s[r]-'a']-pre[l-1][s[r]-'a']>0) return 1;
	//baac
	return ask(l,r)<=r;
}
signed main()
{
	n=read();S=sqrt(n);
	scanf("%s",s+1);
	init1();init2();
	q=read();
	while(q--)
	{
		int l=read(),r=read();
		if(s0(l,r)) puts("-1");
		else if(s1(l,r)) puts("1");
		else if(s2(l,r)) puts("2");
		else if(s3(l,r)) puts("3");
		else puts("4");
	}
}
posted @ 2021-06-15 21:44  C202044zxy  阅读(91)  评论(0编辑  收藏  举报