hdu 5558 | 2015ACM/ICPC亚洲区合肥站 G Alice's Classified Message (后缀自动机)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5558

题意:

说了一大堆。。其实就是询问位置i开始的后缀和以位置[0…i - 1]开始的所有后缀中最大匹配的公共前缀长度

思路:

这个动态的过程很容易想到SAM啊。。

所以就一边匹配。。一边构建SAM就好了。。

需要注意的是,如果有多个最长,需要输出最左边的位置。

因此多维护一个leftmost,表示某个字符串第一次出现的结尾的位置。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :2017年11月08日 星期三 18时50分18秒
  4File Name :4436.cpp
  5************************************************ */
  6
  7#include <bits/stdc++.h>
  8#define PB push_back
  9#define fst first
 10#define sec second
 11#define lson l,m,rt<<1
 12#define rson m+1,r,rt<<1|1
 13#define ms(a,x) memset(a,x,sizeof(a))
 14typedef long long LL;
 15#define pi pair < int ,int >
 16#define MP make_pair
 17
 18using namespace std;
 19const double eps = 1E-8;
 20const int dx4[4]={1,0,0,-1};
 21const int dy4[4]={0,-1,1,0};
 22const int inf = 0x3f3f3f3f;
 23#define MAXALP 30
 24struct state
 25{
 26    int len, link, nxt[MAXALP];
 27    int leftmost; //由于要求出现位置最小的,leftmost表示第一次出现的右端点位置。
 28};
 29const int N =1E5+7;
 30state st[N*2];
 31int sz, last,rt;
 32char s[N];
 33int cnt[2*N],rk[2*N];//for radix sort
 34void sa_init()
 35{
 36    sz = 0;
 37    last = rt = ++sz;
 38    st[1].len = 0;
 39    st[1].link=-1;
 40    ms(st[1].nxt,-1);
 41}
 42void sa_extend(int c,int head)
 43{
 44    int cur = ++sz;
 45    st[cur].len = st[last].len + 1;
 46    st[cur].leftmost = head;
 47    memset(st[cur].nxt, -1, sizeof(st[cur].nxt));
 48    int p;
 49    for (p = last; p != -1 && st[p].nxt[c] == -1; p = st[p].link)
 50        st[p].nxt[c] = cur;
 51    if (p == -1) {
 52        st[cur].link = rt;
 53    } else {
 54        int q = st[p].nxt[c];
 55        if (st[p].len + 1 == st[q].len) {
 56            st[cur].link = q;
 57        } else {
 58            int clone = ++sz ;
 59            st[clone].len = st[p].len + 1;
 60            st[clone].link = st[q].link;
 61            memcpy(st[clone].nxt, st[q].nxt, sizeof(st[q].nxt));
 62            st[clone].leftmost = st[q].leftmost;
 63            for (; p != -1 && st[p].nxt[c] == q; p = st[p].link)
 64                st[p].nxt[c] = clone;
 65            st[q].link = st[cur].link = clone;
 66        }
 67    }
 68    last = cur;
 69}
 70void topo()
 71{
 72    ms(cnt,0); 
 73    for (int i = 1 ; i <= sz ; i++) cnt[st[i].len]++;
 74    for ( int i = 1 ; i <= sz ; i++) cnt[i]+=cnt[i-1];
 75    for (int i = 1 ; i <= sz  ;i++) rk[cnt[st[i].len]--] = i;
 76}
 77string S;
 78void solve (string S)
 79{
 80    sa_init();
 81    int n = S.length();
 82    int i = 0 ;
 83    while (i<n)
 84    {
 85    int now = rt;
 86    int len = 0 ;
 87    while (i<n &&st[now].nxt[S[i]-'a']!=-1)
 88    {
 89        now = st[now].nxt[S[i]-'a'];
 90        len++;
 91        sa_extend(S[i]-'a',i);
 92        i++;
 93    }
 94    if (!len)
 95    {
 96        sa_extend(S[i]-'a',i);
 97        printf("%d %d\n",-1,S[i]);
 98        i++;
 99    }
100    else printf("%d %d\n",len,st[now].leftmost-len+1);
101    }
102}
103
104
105int main()
106{
107#ifndef  ONLINE_JUDGE 
108        freopen("./in.txt","r",stdin);
109#endif
110
111    int T;
112    int cas = 0 ;
113    cin>>T;
114    while (T--)
115    {
116        printf("Case #%d:\n",++cas);
117        cin>>S;
118        solve(S);
119    }
120
121
122#ifndef ONLINE_JUDGE  
123    fclose(stdin);
124#endif
125    return 0;
126}