2020 杭电多校 Isomorphic Strings (KMP/字符串hash)未完善

2020 杭电多校 Isomorphic Strings (KMP/字符串hash)

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6863

题意

给一个字符串 s ,长度为 n ,问是否存在一个 k ,满足 k∣n ,将 s 分成相等的 k 段子串,每一段子串互为循环同构。其中,1≤T≤1000,1≤n≤5⋅106,∑n≤2⋅107。

题解

考虑枚举所有 nn 的因数 kk ,对于每一个 k ,计算出每一个子串的哈希值集合,并且求出第一个子串的所有循环同构的哈希值集合,若第一个集合为第二个的子集则 kk 合法。在判断是可以使用数组来记录,并且使用一个时间戳来标记,不用每次清空。
或者使用 kmp来解决这个问题,对于每一个 k 进行判断的时候,可以将第一个长度为 n/k 的子串复制一遍并接在后面作为 tt,可以知道 tt 中包含所有的循环同构,对于后面的每 n/k的子串都进行与 t 进行匹配,使用 kmp 即可,一次判断的复杂度为 O(n)

AC代码

#include 
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=5e6+10;
int T,n;
char s[N];
int nxt[N];
bool kmp(char *t,char *s)
{
	int ans=0;
	int i,j;
	int len1=strlen(t+1),len2=strlen(s+1);
	nxt[0]=nxt[1]=0;
	for(i=2,j=0; i<=len1; i++)
	{
		while(j&&t[j+1]!=t[i])j=nxt[j];
		if(t[j+1]==t[i])++j;
		nxt[i]=j;
	}
	for(i=1,j=0; i<=len2; i++)
	{
		while(j&&t[j+1]!=s[i])j=nxt[j];
		if(t[j+1]==s[i])++j;
		if(j==len1)
		{
			ans++;
			j=nxt[j];
			return 1;
		}
	}
	return 0;
}
char a[N],b[N];
bool pd(int k)
{
	if(k==1) return 0;
	int len=n/k;
	for(int i=1; i<=len; i++)
	{
		a[i]=s[i];
		a[i+len]=s[i];
	}
	a[2*len+1]='\0';
	for(int i=len; i<=n; i+=len)
	{
		for(int j=1; j<=len; j++)
		{
			b[j]=s[i+j];
		}
		b[len+1]='\0';
		if(kmp(b,a)==0) return 0;
	}
	return 1;

}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		scanf("%s",s+1);
		bool flag=false;
		for(int i=1;i<=n&&!flag; i++)
		{
			if(n%i==0&&(pd(i)))//||pd(n/i)
			{
				flag = true;
			}
		}
		if(!flag) puts("No");
		else puts("Yes");
	}
	return 0;
}

你可能感兴趣的:(补题库)