• 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_lleq ror rt_rgeq l) 就说明合法。第一种情况等价于判断子串 ([l,r]) 是否存在 (border),这是最有趣的问题,我们放在最后解决。

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

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

    证明我还要多想一下

    如果前面的都不是那么答案就是 (4) 了,时间复杂度 (O(nsqrt 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");
    	}
    }
    
  • 相关阅读:
    Objective
    ios 贝塞尔画图
    M端的飞行宝石代码(启发性代码)
    T端单机定时间随机召唤生物的脚本
    T端升级宝石
    Xcode中如何屏蔽某个源文件的编译警告信息
    xcode合并模拟器和真机静态库的编译
    layoutSubviews setNeedsDisplay
    限制只能输入数字字母
    正确使用Block避免Cycle Retain和Crash
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14887314.html
Copyright © 2020-2023  润新知