码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5442 后缀自动机+kmp

时间:2015-09-13 17:21:34      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:

 题目大意:

给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针

 

比赛一直因为处理最小位置出错,一结束就想明白了。。。真是作孽

这里正向后缀自动机跑一遍最大的,这样得到的位置肯定是最小的

而逆时针最大就反向重建后缀自动机再跑一遍最大的,但这样因为后缀自动机跑出的位置是最小的,但返回来就变成最大的位置了

如果存在更小的位置,那么就相当于可以从开头拎出一段移到末尾,那么必然是产生一个循环节,这个长度可以利用kmp来处理

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 using namespace std;
  7 /* run this program using the console pauser or add your own getch, system("pause") or input loop */
  8 #define M 26
  9 #define N 80100
 10 #define ull unsigned long long
 11 char str[N] , tmp[N];
 12 int n , num[N];
 13 queue<int> Q;
 14 
 15 struct SamNode{
 16     SamNode *son[M] , *f;
 17     int l , s;
 18     void init(){
 19         for(int i=0 ; i<M ; i++) son[i] = NULL;
 20         f = NULL;
 21         l = s = 0;
 22     }
 23 };
 24 
 25 SamNode sam[N] , *root , *last;
 26 int cnt;
 27 
 28 void init(){
 29     cnt = 0;
 30     memset(sam , 0 , sizeof(sam));
 31     root = last = &sam[0];
 32 }
 33 
 34 void add(int x){
 35     sam[cnt+1].init();
 36     SamNode *p = &sam[++cnt] , *jp=last;
 37     /*
 38     这里p->s = jp->s+1写成p->s = p->l也是一样的,因为对于每次当前的last来说,
 39     l和s的值是一样的,因为每次当前的last都是处于字符串的位置上的
 40     数,不是额外添加的节点
 41     */
 42     p->l = jp->l+1; p->s = jp->s+1;
 43     last = p;
 44     for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
 45     if(!jp) p->f=root;
 46     else{
 47         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
 48         else{
 49             sam[cnt+1].init();
 50             SamNode *r = &sam[++cnt] , *q = jp->son[x];
 51             *r=*q;
 52             r->l = jp->l+1 ; r->s = p->l;
 53             q->f = p->f = r;
 54             for(; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
 55         }
 56     }
 57 }
 58 ull _hash = 0;
 59 
 60 int _next[N];
 61 int s[N];
 62 void get_next(int *s , int n)
 63 {
 64     _next[0] = _next[1] = 0;
 65     for(int i=2; i <n ; i++){
 66         int j=_next[i-1];
 67         while(j && s[j+1]!=s[i]) j =_next[j];
 68         _next[i] = s[j+1]==s[i]?j+1:0;
 69     }
 70 }
 71 
 72 int solve(int len)
 73 {
 74     SamNode *cur = root;
 75     for(int i=0 ; i<len ; i++){
 76         for(int j=25 ; j>=0 ; j--){
 77             if(cur->son[j]){
 78                 s[i] = j;
 79                 cur = cur->son[j];
 80                 break;
 81             }
 82         }
 83     }
 84     int ret = cur->s-len+1;
 85 
 86     return ret;
 87 }
 88 
 89 int main() {
 90  //  freopen("a.in" , "r" , stdin);
 91 //    freopen("out.txt" , "w" , stdout);
 92     int T;
 93     scanf("%d" , &T);
 94     while(T--){
 95         scanf("%d" , &n);
 96         scanf("%s" , str);
 97         int len = n;
 98         init();
 99         for(int i=0 ; i<len ; i++)
100             str[len+i] = str[i];
101         for(int i=0 ; i<len*2 ; i++)
102             add(str[i]-a);
103       //  for(int i=0 ; i<2*n ; i++) cout<<str[i];
104         //cout<<endl;
105         int ret1 = solve(len);
106 
107         for(int i=0 ; i<len ; i++){
108             tmp[len-i-1] = str[i];
109         }
110         for(int i=0 ; i<len ; i++){
111             tmp[len+i] = tmp[i];
112         }
113 
114         init();
115         for(int i=0 ; i<len*2 ; i++)
116             add(tmp[i]-a);
117         int ret2 = solve(len);
118         ret2 = len-ret2+1;
119       //  cout<<"here: "<<ret1<<" "<<ret2<<endl;
120         get_next(s , n);
121         int del = n-_next[n-1]-1;
122       //  cout<<"try: "<<del<<" "<<_next[n-1]<<endl;
123         if(n%del==0){
124             while(ret2>del) ret2-=del;
125         }
126         // cout<<"here: "<<ret1<<" "<<ret2<<endl;
127       //  cout<<ret1<<" "<<ret2<<endl;
128         int i , j , cnt , pos , wise=-1;
129         for(i=ret1-1 , j=ret2+len-1 , cnt=0 ; cnt<len ; cnt++ , i++ , j--){
130             //    cout<<cnt<<" "<<i<<" "<<j<<" "<<str[i]<<" "<<str[j]<<endl;
131             if(str[i]>str[j]){wise=0;pos=ret1;break;}
132             else if(str[i]<str[j]){wise=1;pos=ret2;break;}
133         }
134         if(wise==-1){
135             if(ret1<ret2) pos = ret1 , wise = 0;
136             else if(ret1>ret2) pos = ret2 , wise = 1;
137             else pos=ret1 , wise=0;
138          //   cout<<"in: "<<endl;
139         }
140         printf("%d %d\n" , pos, wise);
141     }
142     return 0;
143 }

 

HDU 5442 后缀自动机+kmp

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4805137.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!