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");
}
}