CF1043G Speckled Band 题解
题目分析
我们阅读题目后能够很容易的得出答案有解时最大为
- 答案为
-1
那么区间内的字母都只出现一次,所以我们开个字母出现次数的前缀和判断即可。
时间复杂度
- 答案为
1
因为只能出现一种子串,例如
查询时间复杂度为因子个数,SA 预处理时间复杂度
- 答案为
2
答案为
查询时间复杂度
再考虑第三种情况,其实就是判断子串是否有 border。最长 border 比较难求,但是最短 border 就比较简单了。
引理:若串 S 的最小 border 长度超过
所以我们可以考虑平衡规划,对于判断长度小于
我们还要注意一个点,若有一个长度大于
查询时间复杂度
- 答案为
3
答案为
前两种只需判断
第三种情况,我们可以用前面已知的
查询时间复杂度
- 答案为
4
以上都不是直接输出
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+10;
const int inf=LONG_LONG_MAX;
int n,q,m,p,flg;
char s[maxn];
int cnt[maxn][200];
vector<int>g[maxn];
struct SA{
int s[maxn];
int m,p;
int x[maxn],y[maxn],last[maxn],dbf[maxn],t[maxn];
int sa[maxn],rnk[maxn],height[maxn],st[maxn][30];
int cmp(int x,int y,int k){
return last[x]==last[y]&&last[x+k]==last[y+k];
}
void init(){
m=200;
p=0;
memset(t,0,sizeof(t));
memset(height,0,sizeof(height));
memset(x,0,sizeof(x));
for(int i=1;i<=n;i++)t[x[i]=s[i]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i>=1;i--)dbf[t[x[i]]--]=i;
for(int k=1;k<=n;k<<=1,m=p){
p=0;
for(int i=n-k+1;i<=n;i++)y[++p]=i;
for(int i=1;i<=n;i++){
if(dbf[i]>k)y[++p]=dbf[i]-k;
}
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++)t[x[y[i]]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i>=1;i--)dbf[t[x[y[i]]]--]=y[i];
memcpy(last,x,sizeof(x));
p=0;
for(int i=1;i<=n;i++){
x[dbf[i]]=cmp(dbf[i],dbf[i-1],k)?p:++p;
}
if(p==n)break;
}
for(int i=1;i<=n;i++){
sa[i]=dbf[i];
rnk[i]=x[i];
}
p=0;
for(int i=1;i<=n;i++){
if(p)p--;
int j=sa[rnk[i]-1];
while(i+p<=n&&j+p<=n&&s[i+p]==s[j+p])p++;
height[rnk[i]]=p;
st[rnk[i]][0]=height[rnk[i]];
}
for(int j=1;j<=25;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
}
}
int get(int l,int r){
l=rnk[l],r=rnk[r];
if(l>r)swap(l,r);
if(l==r)return n-sa[l]+1;
l++;
int k=__lg(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
}A,B;
struct DSU{
int fa[maxn],val[maxn];
void init(){
for(int i=1;i<=n+1;i++){
fa[i]=i;
val[i]=0x3f3f3f3f;
}
}
int find(int x){
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void update(int l,int r,int k){
if(l>r)return ;
int p=find(l);
while(p<=r){
val[p]=k;
fa[p]=p+1;
p=find(p);
}
}
}pre,suf;
int st[maxn][25];
void init(){
for(int i=1;i<=n;i++){
A.s[i]=s[i];
B.s[i]=s[n-i+1];
}
A.init();
B.init();
pre.init();
suf.init();
for(int i=1;i<=n;i++){
cnt[i][s[i]]++;
}
for(int i=1;i<=n;i++){
for(int j='a';j<='z';j++){
cnt[i][j]+=cnt[i-1][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j*j<=i;j++){
if(i%j==0){
if(j!=i)g[i].push_back(j);
if(i/j!=i&&i/j!=j)g[i].push_back(i/j);
}
}
}
for(int len=1;len*2<=n;len++){
for(int i=len,j=len*2;j<=n;i+=len,j+=len){
int lcp=A.get(i,j);
int lcs=B.get(n-i+1,n-j+1);
int l=i-lcs+1,r=j+lcp-1;
pre.update(l,r-2*len+1,2*len);
suf.update(l+2*len-1,r,2*len);
}
}
for(int i=1;i<=n;i++)st[i][0]=i+pre.val[i]-1;
for(int j=1;j<=20;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
}
}
int solve1(int l,int r){
flg=1;
for(int i='a';i<='z';i++){
if(cnt[r][i]-cnt[l-1][i]>1)flg=0;
}
return flg;
}
int solve2(int l,int r){
flg=0;
for(int i=0;i<g[r-l+1].size();i++){
if(A.get(l,l+g[r-l+1][i])>=r-l+1-g[r-l+1][i]){
flg=1;
break;
}
}
return flg;
}
int solve3(int l,int r){
if(pre.val[l]<=r-l+1||suf.val[r]<=r-l+1){
return 1;
}
int sq=sqrt(n);
for(int i=1;i<=sq&&i<r-l+1;i++){
if(A.get(l,r-i+1)>=i&&2*i<=r-l+1)return 1;
}
int res=0x3f3f3f3f;
for(int i=max(1ll,A.rnk[l]-sq+1);i<=min(n,A.rnk[l]+sq-1);i++){
int p=A.sa[i];
if(p>l&&p<=r&&A.get(l,p)>=r-p+1)res=min(res,r-p+1);
}
if(res*2<=r-l+1)return 1;
return 0;
}
int get(int l,int r){
if(l>r)return 0x3f3f3f3f;
int k=__lg(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int solve4(int l,int r){
if((cnt[r-1][s[l]]-cnt[l][s[l]])||(cnt[r-1][s[r]]-cnt[l][s[r]]))return 1;
if(get(l+1,r-1)<r)return 1;
return 0;
}
signed main(){
scanf("%lld",&n);
scanf("%s",s+1);
init();
scanf("%lld",&q);
while(q--){
int l,r;
scanf("%lld%lld",&l,&r);
if(solve1(l,r))puts("-1");
else if(solve2(l,r))puts("1");
else if(solve3(l,r))puts("2");
else if(solve4(l,r))puts("3");
else puts("4");
}
return 0;
}