参考资料:
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;
}