BZOJ 2882 工艺 ——后缀自动机 最小表示法

先说后缀自动机的做法。

直接把S串复制一遍成SS,然后建立后缀自动机,go边相当于在当前字符的后面插入,而son边可以看作在字符串前面加一个字符。

所以贪心的走字典序最小的边即可,而且根据后缀自动机的构建的性质,是一定可以走够len的,然后输出即可。

人生第一个后缀自动机的代码。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<cstdio>
#define N 600003
using namespace std;
int n,m,cnt,nq,np,p,q,last,root;
map<int,int> ch[N*2];
int fa[N*2],l[N*2],a[N];
void extend(int x)
{
    int c=a[x];
    p=last; np=++cnt; last=np;
    l[np]=x;
    for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
    if (!p) fa[np]=root;
    else {
        q=ch[p][c];
        if (l[q]==l[p]+1) fa[np]=q;
        else {
            nq=++cnt; l[nq]=l[q]+1;
            ch[nq]=ch[q];
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
        }
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) a[n+i]=a[i];
    m=2*n;
    last=root=++cnt; ch[N].clear();
    for (int i=1;i<=m;i++) extend(i);
    p=1;
    map<int,int>::iterator t;
    for (int i=1;i<=n;i++) {
        t=ch[p].begin();
        p=t->second;
        if (i!=n) printf("%d ",t->first);
        else printf("%d
",t->first);
    }
}

然后再来说说最小表示法,大概的思想就是用两个指针来比较,然后不相等的时候就会排除很大的一片区间,然后最后剩下的就是最优解,最大表示法同理,写完后跑的飞快。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define maxn 300005
int n,a[maxn],pos;
 
int main()
{
    scanf("%d",&n);
    F(i,1,n) scanf("%d",&a[i]);
    int i=1,j=2,k=0,flag=0;
    while (i<=n&&j<=n)
    {
        k=0;
//      printf("%d %d
",i,j); 
        while (a[(i+k-1)%n+1]==a[(j+k-1)%n+1]&&k<=n) k++;
        if (k==n) {pos=i;flag=1;}
        else
        {
            if (a[(i+k-1)%n+1]>a[(j+k-1)%n+1])
            {
                if (i+k+1<=j) i=j+1;
                else i=i+k+1;
            }
            else
            {
                if (j+k+1<=i) j=i+1;
                else j=j+k+1;
            }
        }
    }
    if (!flag) pos=min(i,j);
    F(i,1,n) printf("%d%c",a[(pos+i-2)%n+1],i==n?'
':' ');
}

  

原文地址:https://www.cnblogs.com/SfailSth/p/6486717.html