• HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)


    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;
    }
    View Code
  • 相关阅读:
    谈执着
    SQL表自连接用法
    Mysql group by 排序问题
    php自动生成mysql的触发代码。
    XSS CSRF 攻击
    [微信开发利器]微信内移动前端开发抓包调试工具fiddler使用教程
    微信JS-SDK]微信公众号JS开发之卡券领取功能详解
    优化与重构的思考
    c语言 13
    c语言 13
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/10693226.html
Copyright © 2020-2023  润新知