CF444D DZY Loves Strings 根号分治

题意:

戳这里

分析:

巨佬说这题是根号分治裸题,我还是太菜了

  • 暴力

对于每一个询问,扫一遍原序列,求出 (a) 出现每一个位置,然后对于 (b) 一遍枚举出现的位置,一边双指针找出离 (b) 最近的 (a) 出现的位置,复杂度 (O(qn))

  • 正解

我们发现,对于一个长为 (n) 的字符串,里面互不相同的长度小于 4 的子串只有 (4n) 个,其中出现次数大于 (sqrt{4n}) 的串不超过 (sqrt{4n})

  1. (a,b) 出现次数都小于 (sqrt{4n})

我们直接按照原来的双指针枚举就行了,由于两个串出现的次数都不超过 (sqrt{4n}) ,所以此时的复杂度是 (sqrt{4n})

  1. (a,b) 至少有一个出现次数大于 (sqrt{4n})

预处理它和每一个串的最小答案,由于这样的串不超过 (sqrt{4n}) 个,所以总的复杂度不超过 (O(sqrt{4n}))

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second

using namespace std;

namespace zzc
{
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxq = 5e5+5;
	const int maxn = 1e5+5;
	const int maxm = 5e5+5;
	const int blo = 400;
	char s[maxn],a[10],b[10];
	int mp[maxq],f[blo][maxn],id[maxn][5],len[maxn],big[maxn];
	int n,idx,cnt,qt;
	vector<int> pos[maxn];
	
	int get(char *s,int l)
	{
		int res=0;
		for(int i=0;i<l;i++) res=res*26+(s[i]-96);
		return res;
	}
	
	void work()
	{
		scanf("%s",s+1);qt=read();n=strlen(s+1);
		for(int l=1;l<=4;l++)
		{
			for(int i=1,j=n-l+1;i<=j;i++)
			{
				int tmp=get(s+i,l);
				if(!mp[tmp]) mp[tmp]=++idx,len[idx]=l;
				pos[id[i][l]=mp[tmp]].pb(i);
			}
		}
		for(int i=1;i<=idx;i++)if(pos[i].size()>blo)
		{
			big[i]=++cnt;
			int sz=pos[i].size(),tmp=len[i];
			memset(f[cnt],0x3f,sizeof(f[cnt]));
			for(int j=1;j<sz;j++)
			{
				int lef=pos[i][j-1];
				int rig=pos[i][j];
				for(int k=lef;k<rig;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],min(max(k+l-lef,tmp),max(rig+tmp-k,l)));
			}
			for(int k=pos[i][sz-1],lef=pos[i][sz-1];k<=n;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],max(k+l-lef,tmp));
			for(int k=1,rig=pos[i][0];k<rig;k++) for(int l=1;l<=4;l++) f[cnt][id[k][l]]=min(f[cnt][id[k][l]],max(rig+tmp-k,l));
		}
		while(qt--)
		{
			scanf("%s",a);scanf("%s",b);
			int x=mp[get(a,strlen(a))],y=mp[get(b,strlen(b))];
			if(!x||!y) printf("-1
");
			else if(big[x]) printf("%d
",f[big[x]][y]);
			else if(big[y]) printf("%d
",f[big[y]][x]);
			else
			{
				int sz1=pos[x].size()-1,sz2=pos[y].size()-1,lx=len[x],ly=len[y],ans=0x3f3f3f3f,now=0;
				for(int i=0;i<=sz1;i++)
				{
					while(now<sz2&&pos[y][now]<pos[x][i]) now++;
					if(pos[y][now]>pos[x][i])
					{
						ans=min(ans,pos[y][now]+ly-pos[x][i]);
						if(now) ans=min(ans,pos[x][i]+lx-pos[y][now-1]);
					}
					else ans=min(ans,pos[x][i]+lx-pos[y][now]);
				}
				printf("%d
",max(ans,max(lx,ly)));
			}
		}
	}

}

int main()
{
	zzc::work();
	return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/14070744.html