[SAM] POJ1509 Glass Beads

题意

给定n,求最小循环子串的开头位置。
若有多个答案,输出开头位置最小的。
n<=10000

题解

SAM 最水的模板题。
把串复制一段接在后面,然后在SAM上走,每次选标号最小的边走,走n步就达到了答案状态。
我们还需要输出位置。就相当于求子串在原串中首次出现位置,这个问题我们可以对每个状态维护 Right 集合的最小元素 Firpos 来解决。
在维护时,显然之前的状态的 Firpos 是不会变得更小的。
新建 np 时, Firpos(np)=Firpos(last)+1 .
新建 nq 时, Firpos(nq)=Firpos(q) . 都很显然。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=20005;
struct node{
    node *par,*ch[26]; int _max,firpos;
} *root, *last, base[850000], *p_top=base;
typedef node* P_node;
int res;
P_node newnode(int t1=0){
    p_top->par=0; p_top->_max=p_top->firpos=t1;
    memset(p_top->ch,0,sizeof(p_top->ch));
    return p_top++;
}
void Extend(char x){
    P_node p=last, np=newnode(p->_max+1);
    while(p&&p->ch[x]==0) p->ch[x]=np, p=p->par;
    if(!p) np->par=root; else{
        P_node q=p->ch[x];
        if(q->_max==p->_max+1) np->par=q; else{
            P_node nq=newnode(p->_max+1); nq->firpos=q->firpos;
            memcpy(nq->ch,q->ch,sizeof(q->ch));
            nq->par=q->par; q->par=nq; np->par=nq; 
            while(p&&p->ch[x]==q) p->ch[x]=nq, p=p->par;
        }
    }
    last=np;
}
int _test,n;
char s[maxn];
int main(){
    freopen("poj1509.in","r",stdin);
    freopen("poj1509.out","w",stdout);
    scanf("%d",&_test);
    while(_test--){
        scanf("%s",s+1); n=strlen(s+1);
        for(int i=1;i<=n;i++) s[i+n]=s[i];
        p_top=base; last=root=newnode(0);
        for(int i=1;i<=n*2;i++) Extend(s[i]-'a');
        P_node p=root;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=25;j++) if(p->ch[j]){ p=p->ch[j]; break; }
        }
        printf("%d\n",p->firpos-n+1);
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值