http://acm.hdu.edu.cn/showproblem.php?pid=5442
题目大意:
给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针
后缀自动机上s记录达到的最长的位置,如果不更新,那么必然一次跑完得到的是最小位置,那么为了得到最大,之前更新每一个节点中的s,只有儿子位置上的能更新父亲
所以先将后缀自动机拓扑排序,然后从后往前,不断将父亲的s更新成更大的s
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; /* run this program using the console pauser or add your own getch, system("pause") or input loop */ #define M 26 #define N 80100 #define ull unsigned long long char str[N] , tmp[N]; int n , num[N]; queue<int> Q; struct SamNode{ SamNode *son[M] , *f; int l , s; void init(){ for(int i=0 ; i<M ; i++) son[i] = NULL; f = NULL; l = s = 0; } }*b[N]; SamNode sam[N] , *root , *last; int cnt; void init(){ cnt = 0; sam[0].init(); root = last = &sam[0]; } void add(int x){ sam[cnt+1].init(); SamNode *p = &sam[++cnt] , *jp=last; /* 这里p->s = jp->s+1写成p->s = p->l也是一样的,因为对于每次当前的last来说, l和s的值是一样的,因为每次当前的last都是处于字符串的位置上的 数,不是额外添加的节点 */ p->l = jp->l+1; p->s = jp->s+1; last = p; for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p; if(!jp) p->f=root; else{ if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x]; else{ sam[cnt+1].init(); SamNode *r = &sam[++cnt] , *q = jp->son[x]; *r=*q; r->l = jp->l+1 ; r->s = p->l; q->f = p->f = r; for(; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r; } } } int solve(int len) { SamNode *cur = root; for(int i=0 ; i<len ; i++){ for(int j=25 ; j>=0 ; j--){ if(cur->son[j]){ cur = cur->son[j]; break; } } } int ret = cur->s-len+1; return ret; } int solve1(int len) { memset(num , 0 , sizeof(num)); for(int i=1 ; i<=cnt ; i++) num[sam[i].l]++; for(int i=1 ; i<=len*2 ; i++) num[i] += num[i-1]; for(int i=1 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i]; for(int i=cnt-1 ; i>=0 ; i--){ b[i]->f->s = max(b[i]->f->s , b[i]->s); } SamNode *cur = root; for(int i=0 ; i<len ; i++){ for(int j=25 ; j>=0 ; j--){ if(cur->son[j]){ cur = cur->son[j]; break; } } } int ret = cur->s-len+1; return ret; } int main() { // freopen("a.in" , "r" , stdin); // freopen("out.txt" , "w" , stdout); int T; scanf("%d" , &T); while(T--){ scanf("%d" , &n); scanf("%s" , str); int len = n; init(); for(int i=0 ; i<len ; i++) str[len+i] = str[i]; for(int i=0 ; i<len*2 ; i++) add(str[i]-'a'); // for(int i=0 ; i<2*n ; i++) cout<<str[i]; //cout<<endl; int ret1 = solve(len); for(int i=0 ; i<len ; i++){ tmp[len-i-1] = str[i]; } for(int i=0 ; i<len ; i++){ tmp[len+i] = tmp[i]; } init(); for(int i=0 ; i<len*2-1 ; i++) add(tmp[i]-'a'); int ret2 = len-solve1(len)+1; // cout<<"here: "<<ret1<<" "<<ret2<<endl; // cout<<ret1<<" "<<ret2<<endl; int i , j , cnt , pos , wise=-1; for(i=ret1-1 , j=ret2+len-1 , cnt=0 ; cnt<len ; cnt++ , i++ , j--){ // cout<<cnt<<" "<<i<<" "<<j<<" "<<str[i]<<" "<<str[j]<<endl; if(str[i]>str[j]){wise=0;pos=ret1;break;} else if(str[i]<str[j]){wise=1;pos=ret2;break;} } if(wise==-1){ if(ret1<ret2) pos = ret1 , wise = 0; else if(ret1>ret2) pos = ret2 , wise = 1; else pos=ret1 , wise=0; // cout<<"in: "<<endl; } printf("%d %d " , pos, wise); } return 0; }