bzoj2882 工艺(后缀自动机(最小表示法))

本文介绍了一道题目BZOJ2882的解题思路及实现代码,该题要求通过特定操作找到由方块构成的长条工艺品的最漂亮形态。采用字符串最小表示法结合SAM(Suffix Array Manber)算法解决。

bzoj2882 工艺

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=2882

题意:
小敏和小燕是一对好朋友。
他们正在玩一种神奇的游戏,叫Minecraft。
他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。

数据范围
n<=300000

题解:
求一个字符串的最小表示。
把S复制一遍接在后面,对于这个新串建立SAM,
于是从root开始走len次就是那个最小表示。

字符集很大用map。

等学了最小表示法再来UPD一发。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int N=600005;
struct node
{
    int pa,len;
    map<int,int> ch;
}tr[2*N+100];
int s[N],n,root=0,last=0,tail=0,tmp;
void add(int c)
{
    int nd=++tail; tr[nd].len=tr[last].len+1; 
    for(tmp=last;tmp&&!tr[tmp].ch[c];tmp=tr[tmp].pa) tr[tmp].ch[c]=nd;
    if(!tmp) tr[nd].pa=root;
    else
    {
        int B=tr[tmp].ch[c];
        if(tr[B].len==tr[tmp].len+1) tr[nd].pa=B;
        else
        {
            int nB=++tail;
            tr[nB]=tr[B]; tr[nB].len=tr[tmp].len+1;
            for(;tr[tmp].ch[c]==B;tmp=tr[tmp].pa) 
            tr[tmp].ch[c]=nB;
            tr[nd].pa=nB; tr[B].pa=nB;
        }
    }
    last=nd;
}
void getans()
{
    int tmp=root;
    map<int,int>::iterator p;
    for(int i=1;i<=n;i++)
    {
        p=tr[tmp].ch.begin();
        if(i!=n) printf("%d ",p->first); else printf("%d\n",p->first);
        tmp=p->second;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    for(int i=n+1;i<=2*n;i++) s[i]=s[i-n];
    root=last=++tail;
    for(int i=1;i<=2*n;i++) add(s[i]);
    getans();   
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值