↓ 跳过正文
  1. Posts/

poj 1509 Glass Beads (后缀自动机求最小循环表示)

·652 字·2 分钟

题意:
#

给定一个循环字符串,问字典序最小的串的开始位置。

思路:
#

之前用poj 1509 解题报告-字符串的最小表示法 A过

字符串的最小表示法的复杂度是O(n),代码也不是很难写,不过由于最近在学SAM,所以用SAM写了一下。

参照张天扬的论文:

把原串复制一遍到后面,然后构建后缀自动机。

从初始状态开始,每次走字典序最小的转移,走|S|之后得到的就是最小循环表示。

如果求的是最小后缀,就在原串后加入一个比字符集中所有字符的字典序都小的字符作为终止后,再添加一遍原串。

代码实现
  1/* ***********************************************
  2Author :111qqz
  3Created Time :2017年11月03日 星期五 18时20分42秒
  4File Name :2774_SAM.cpp
  5************************************************ */
  6
  7//#include <bits/stdc++.h>
  8#include <iostream>
  9#include <cstdio>
 10#include <algorithm>
 11#include <cmath>
 12#include <string>
 13#include <cstring>
 14#define PB push_back
 15#define fst first
 16#define sec second
 17#define lnxt l,m,rt<<1
 18#define rnxt m+1,r,rt<<1|1
 19#define ms(a,x) memset(a,x,sizeof(a))
 20typedef long long LL;
 21#define pi pair < int ,int >
 22#define MP make_pair
 23
 24using namespace std;
 25const double eps = 1E-8;
 26const int dx4[4]={1,0,0,-1};
 27const int dy4[4]={0,-1,1,0};
 28const int inf = 0x3f3f3f3f;
 29
 30const int maxn = 5E5;
 31
 32struct node{
 33    node*nxt[26],*fail;
 34    LL len,cnt;
 35};
 36struct SAM{
 37    node no[maxn];
 38    node*root;
 39    int cnt;
 40    node*newnode(){
 41    ms(no[cnt].nxt,0);
 42    no[cnt].fail=NULL;
 43    no[cnt].len = no[cnt].cnt = 0;
 44    return &no[cnt++];
 45    }
 46    void init()
 47    {
 48    cnt = 0;
 49    root = newnode();
 50    }
 51    SAM(){
 52    cnt = 0;
 53    root = newnode();
 54    }
 55    node*add(int c,node*p){
 56        node*cur = newnode();
 57        cur->len = p->len+1;
 58        while(p&&!p->nxt[c]){
 59            p->nxt[c] = cur;
 60            p = p->fail;
 61        }
 62        if(!p){
 63            cur->fail = root;
 64            return cur;
 65        }
 66        node*q = p->nxt[c];
 67        if(p->len+1==q->len){
 68            cur->fail = q;
 69        }else{
 70            node*nq = newnode();
 71            *nq = *q;
 72            q->fail = cur->fail = nq;
 73            nq->len = p->len+1;
 74            while(p&&p->nxt[c]==q){
 75                p->nxt[c] = nq;
 76                p = p->fail;
 77            }
 78        }
 79        return cur;
 80    }
 81    int calc(int L)
 82    {
 83    node *p =root;
 84    for ( int i = 0 ; i < L ; i++)
 85    {
 86        bool flag = false;
 87        for ( int j = 0 ; j < 26 ; j++) //找字典序最小的.
 88        if (p->nxt[j])
 89        {
 90            flag = true;
 91            p=p->nxt[j];
 92            break;
 93        }
 94        if (!flag) break;
 95    }
 96    return p->len + 1 - L;
 97    }
 98};
 99SAM sam;
100string A,B;
101int main()
102{
103    #ifndef  ONLINE_JUDGE
104        freopen("./in.txt","r",stdin);
105  #endif
106    int T;
107    cin>>T;
108    while (T--)
109    {
110        sam.init();
111        node *cur =sam.root;
112        cin>>A;
113        for ( int i = 0 ; i < A.length() ; i++) cur = sam.add(A[i]-'a',cur);
114        for ( int i = 0 ; i < A.length() ; i++) cur = sam.add(A[i]-'a',cur);
115        int ans = sam.calc(A.length());
116        printf("%d\n",ans);
117    }
118
119  #ifndef ONLINE_JUDGE
120  fclose(stdin);
121  #endif
122    return 0;
123}

相关文章

hdu 3374 String Problem (字符串的最小/大表示法+kmp)

hdu 3374 题目链接 题意:给出一个循环字符串,问最小表示出现的位置以及次数,最大表示出现的位置以及次数。 思路:之前只写过最小表示。。最大表示其实是一样的。。。把不等式方向变号即可。。。对于出现的次数。。。其实就等同于这个字符串是由几个子串组成。。。跑一遍kmp。。答案为len-nxt[len],1A

hdu 2609 How many (字符串的最小表示法+set)

hdu 2609 题目链接 题意:给出n个循环字符串,问有多少种。 思路:将每个字符串换成最小表示,然后set存一下即可。 代码实现 1/* *********************************************** 2Author :111qqz 3Created Time :2016年08月13日 星期六 02时44分21秒 4File Name :code/hdu/2609.cpp 5************************************************ */ 6#include <cstdio> 7#include <cstring> 8#include <iostream> 9#include <algorithm> 10#include <vector> 11#include <queue> 12#include <stack> 13#include <set> 14#include <map> 15#include <string> 16#include <cmath> 17#include <cstdlib> 18#include <deque> 19#include <ctime> 20#define fst first 21#define sec second 22#define lson l,m,rt<<1 23#define rson m+1,r,rt<<1|1 24#define ms(a,x) memset(a,x,sizeof(a)) 25typedef long long LL; 26#define pi pair < int ,int > 27#define MP make_pair 28using namespace std; 29const double eps = 1E-8; 30const int dx4[4]={1,0,0,-1}; 31const int dy4[4]={0,-1,1,0}; 32const int inf = 0x3f3f3f3f; 33const int N=1E4+7; 34int n; 35char s[N][105]; 36set<string>se; 37int minRep(char *s) 38{ 39 int n = strlen(s); 40 int i = 0 ; 41 int j = 1 ; 42 int k = 0 ; 43 while (i<n&&j<n&&k<n) 44 { 45 int t = s[(i+k)%n] - s[(j+k)%n]; 46 if (t==0) k++; 47 else 48 { 49 if (t>0) 50 i+=k+1; 51 else j+=k+1; 52 if (i==j) j++; 53 k = 0 ; 54 } 55 } 56 return i<j?i:j; 57} 58int main() 59{ 60 #ifndef ONLINE_JUDGE 61 freopen("code/in.txt","r",stdin); 62 #endif 63 while (~scanf("%d",&n)) 64 { 65 ms(s,0); 66 se.clear(); 67 // cout<<"n:"<<n<<endl; 68 char tmp[105]; 69 for ( int i = 0 ; i < n; i++) 70 { 71 scanf("%s",tmp); 72// cout<<"tmp:"<<tmp<<endl; 73 int k = minRep(tmp); 74// cout<<"k:"<<k<<endl; 75 int cnt = 1; 76 int len = strlen(tmp); 77 for ( int j = k ; cnt <= len ; j++,cnt++) 78 s[i][cnt-1] = tmp[j%len]; 79 se.insert(string(s[i])); 80 } 81// for ( int i = 0 ; i < n; i++) cout<<"s[i]:"<<s[i]<<endl; 82// 83 int ans = se.size(); 84 printf("%d\n",ans); 85 } 86 #ifndef ONLINE_JUDGE 87 fclose(stdin); 88 #endif 89 return 0; 90}