字符串最小表示法

参考资料:

https://oi-wiki.org/string/minimal-string/

https://blog.csdn.net/w4149/article/details/76254421


问题:给出一个字符串(s),求出这个字符串的所有循环同构串中字典序最小的。

首先有个暴力(直接复制oi-wiki的标):

大概是两个指针(i,j)。记(k)为公共前缀,尝试扩展(k)到不能扩展为止。如果(k<n)则可以得到两个指针开头的循环同构串的大小关系,将比较大的右移,继续做。

int k = 0, i = 0, j = 1;
while (k < n && i < n && j < n) {
  if (sec[(i + k) % n] == sec[(j + k) % n]) {
    ++k;
  } else {
    if (sec[(i + k) % n] > sec[(j + k) % n])
      ++i;
    else
      ++j;
    k = 0;
    if (i == j) i++;
  }
}
i = min(i, j);

这个暴力显然是(O(n^2))的。

(S_{ldots r})一段区间的字符串,(S_{ldots l+n-1})考虑(S_{idots i+k-1}=S_{j dots j+k-1})(S_{i+k}>S_{j+k}),对于任意(lin [0,k]),都有(S_{i+ldots i+l+n-1}>S_{j+ldots j+l+n-1})。于是(i)可以直接跳到(i+k+1),当然由于小于等于(j)的都被检验过不是最小的了(否则(i)(j)必然有个被替换),所以是跳到(max(i+k+1,j+1))

然后这样就是(O(n))的了。


https://www.cnblogs.com/jz-597/p/13966386.html

这题用最小表示法来判断相等。

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define N 105
#define ll long long
#define mo 998244353
#define jd 19260817
ll qpow(ll x,ll y){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n;
int e[N][N],ne[N];
int re[N][N];
int f[N][N][N];
int vis[N];
int idc[N];
int minidc(int a[],int n){
	int i=0,j=1,k=0;
	while (i<n && j<n){
		for (k=0;k<n && a[(i+k)%n]==a[(j+k)%n];++k)
			k++;
		if (k==n) break;
		if (a[(i+k)%n]>a[(j+k)%n])
			i=max(i+k+1,j+1);
		else
			j=max(j+k+1,i+1);
	}
	i=min(i,j);
	ll res=0;
	for (int j=0;j<n;++j)
		res=(res*jd+a[(i+j)%n])%mo;
	return res;
}
bool same(int x,int y){
	if (ne[x]!=ne[y]) return 0;
	return idc[x]==idc[y];
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		scanf("%d",&ne[i]);
		for (int j=0;j<ne[i];++j){
			scanf("%d",&e[i][j]);
			re[i][e[i][j]]=j;
		}
	}
	for (int i=1;i<=n;++i)
		for (int j=0;j<ne[i];++j)
			f[0][i][j]=ne[i];
	for (int k=1;k<=n;++k)
		for (int i=1;i<=n;++i)
			for (int j=0;j<ne[i];++j){
				int y=e[i][j];
				ll key=0;
				for (int t=re[y][i];t<ne[y];++t)
					key=(key*jd+f[k-1][y][t])%mo;
				for (int t=0;t<re[y][i];++t)
					key=(key*jd+f[k-1][y][t])%mo;
				f[k][i][j]=key;
			}
	for (int i=1;i<=n;++i)
		idc[i]=minidc(f[n][i],ne[i]);
//	for (int i=1;i<=n;++i){
//		printf("i=%d : %d
",i,idc[i]);
//		for (int j=0;j<ne[i];++j)
//			printf("%d ",f[n][i][j]);
//		printf("
");
//	}
	int bz=0;
	for (int i=1;i<=n;++i)
		if (!vis[i]){
			vis[i]=1;
			static int q[N];
			int k=1;
			q[1]=i;
			for (int j=i+1;j<=n;++j)
				if (!vis[j] && same(i,j)){
					vis[j]=1;
					q[++k]=j;
				}
			if (k>1){
				for (int j=1;j<=k;++j)
					printf("%d ",q[j]);
				printf("
");
				bz=1;
			}
		}
	if (bz==0)
		printf("none
");
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/13966523.html