• hdu5442 Favorite Donut


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5442

    题目大意:给你一个长度为n的字符串,将它首尾相连成环。问你这个环上找一个长度为n的字典序最大的串(你可以沿顺时针或逆时针找),如果有多个这样的串,输出首字母标号最小的,如果还有多个,输出顺时针的

    解:

    1、最小表示法解(时间复杂度:O(n))

    最小表示法~

    2、后缀数组(时间复杂度:O(logn))

    比赛的时候想到的方法,然而并没有写出来,不好写+高时间复杂度=不推荐

    最小表示法:

     1 /*
     2  * Problem:  
     3  * Author:  SHJWUDP
     4  * Created Time:  2015/9/16 星期三 16:18:36
     5  * File Name: 1001.cpp
     6  * State: 
     7  * Memo: 
     8  */
     9 #include <iostream>
    10 #include <cstdio>
    11 #include <vector>
    12 #include <cstring>
    13 #include <algorithm>
    14 
    15 using namespace std;
    16 
    17 struct KMP {
    18     int n;
    19     string T;    //target string
    20     vector<int> nt;
    21     KMP(const char * _str) {
    22         n=strlen(_str);
    23         T.assign(_str, _str+n);
    24         getFail();
    25     }
    26     void getFail() {
    27         nt.resize(n+1);
    28         nt[0]=-1;
    29         for(int i=0, j=-1; i<n; ) {
    30             if(j==-1 || T[i]==T[j]) {
    31                 nt[++i]=++j;
    32             } else j=nt[j];
    33         }
    34     }
    35     int match(const char * P) {//pattern string
    36         //在P中找T
    37         int ret=-1;
    38         for(int i=0, j=0; P[i]; ) {
    39             if(j==-1 || P[i]==T[j]) {
    40                 ++i;
    41                 if(++j==n) {
    42                     if(P[i]) ret=i-n;
    43                 }
    44             } else j=nt[j];
    45         }
    46         return ret;
    47     }
    48 };
    49 
    50 int maximum_representation(const char * s) {
    51     int i, j, k, len=strlen(s);
    52     for(i=0, j=1, k=0; i<len && j<len && k<len; ) {
    53         int tmp=s[(i+k)%len]-s[(j+k)%len];
    54         if(tmp==0) ++k;
    55         else {
    56             if(tmp>0) j+=k+1;//改成小于号是最小表示法
    57             else i+=k+1;
    58             if(i==j) ++j;
    59             k=0;
    60         }
    61     }
    62     return min(i, j);
    63 }
    64 
    65 int n;
    66 int main() {
    67 #ifndef ONLINE_JUDGE
    68     freopen("in", "r", stdin);
    69     //freopen("out", "w", stdout);
    70 #endif
    71     int T;
    72     scanf("%d", &T);
    73     while(T--) {
    74         scanf("%d", &n);
    75         string str1;
    76         cin>>str1;
    77         int pos1=maximum_representation(str1.c_str());
    78         string str2(str1.rbegin(), str1.rend());
    79         int pos2=maximum_representation(str2.c_str());
    80         str1+=str1;
    81         str2+=str2;
    82         KMP kmp(str2.substr(pos2, n).c_str());
    83         pos2=kmp.match(str2.c_str());
    84         auto cmp=[&]()->bool {
    85             for(int i=0; i<n; ++i) {
    86                 if(str1[pos1+i]!=str2[pos2+i])
    87                     return str1[pos1+i]>str2[pos2+i];
    88             }
    89             return pos1<=n-pos2-1;
    90         };
    91         if(cmp()) {
    92             printf("%d 0
    ", pos1+1);
    93         } else {
    94             printf("%d 1
    ", n-pos2);
    95         }
    96     }
    97     return 0;
    98 }
    View Code

    后缀数组:

      1 /*
      2  * Problem:  
      3  * Author:  SHJWUDP
      4  * Created Time:  2015/9/14 星期一 16:06:34
      5  * File Name: 1001.cpp
      6  * State: 
      7  * Memo: 
      8  */
      9 #include <iostream>
     10 #include <cstdio>
     11 #include <vector>
     12 #include <cstring>
     13 #include <algorithm>
     14 
     15 using namespace std;
     16 
     17 struct SuffixArray {
     18     static const int SIGMA_SIZE=256;
     19     int n;//串长+1
     20     vector<int> str;//str中最后一个元素为0
     21     vector<int> sa;//第i大后缀为str[sa[i]:]
     22     vector<int> rank;//str坐标为i的后缀的字典序排名
     23     vector<int> height;//sa[i-1]和sa[i]的最长公共前缀(LCP)
     24     SuffixArray(const char * _str) {
     25         n=strlen(_str)+1;
     26         str.resize(n);
     27         for(int i=0; i<n; ++i) str[i]=_str[i];
     28         build_sa();
     29     }
     30     void build_sa(int m=SIGMA_SIZE) {
     31         sa.assign(n, 0);
     32         vector<int> x(n, 0), y(n, 0), c(m, 0);//c(字符计数)
     33         //x[i]:str坐标为i的x值rank
     34         //y[i]:y值第i大的str坐标
     35         //*y数组中前k个为y段串不足k长度的串对应str坐标
     36         for(int i=0; i<n; ++i) ++c[x[i]=str[i]];
     37         for(int i=1; i<m; ++i) c[i]+=c[i-1];
     38         for(int i=n-1; i>=0; --i) sa[--c[x[i]]]=i;
     39         for(int k=1; k<=n; k<<=1) {
     40             int p=0;
     41             //直接利用sa数组排序第二关键字
     42             for(int i=n-k; i<n; ++i) y[p++]=i;
     43             for(int i=0; i<n; ++i) if(sa[i]>=k) y[p++]=sa[i]-k;
     44             //基数排序第一关键字
     45             c.assign(m, 0);
     46             for(int i=0; i<n; ++i) ++c[x[y[i]]];
     47             for(int i=1; i<m; ++i) c[i]+=c[i-1];
     48             for(int i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i];
     49             //根据sa和y数组计算新的x数组
     50             swap(x, y);
     51             p=1; x[sa[0]]=0;
     52             for(int i=1; i<n; ++i) {
     53                 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
     54             }
     55             if(p >= n)break;
     56             m = p;//下次基数排序的最大值
     57         }
     58         getHeight();
     59     }
     60     void getHeight() {
     61         rank.resize(n);
     62         height.resize(n);
     63         for(int i=1; i<n; ++i) rank[sa[i]]=i;
     64         for(int i=0, k=0; i<n-1; ++i) {
     65             //h[i]=height[rank[i]]
     66             if(k) --k;    //h[i]>=h[i-1]-1
     67             int j=sa[rank[i]-1];
     68             while(str[i+k]==str[j+k]) ++k;
     69             height[rank[i]]=k;
     70         }
     71     }
     72 };
     73 
     74 int n;
     75 bool cmp(string a, string b, int x, int y) {
     76     for(int i=0; i<n; ++i) {
     77         if(a[x+i]!=b[y+i]) return a[x+i]>b[y+i];
     78     }
     79     return x<=n-y-1;
     80 }
     81 int main() {
     82 #ifndef ONLINE_JUDGE
     83     freopen("in", "r", stdin);
     84     //freopen("out", "w", stdout);
     85 #endif
     86     int T;
     87     scanf("%d", &T);
     88     while(T--) {
     89         scanf("%d", &n);
     90         string str1;
     91         cin>>str1;
     92         string str2(str1.rbegin(), str1.rend());
     93         str1+=str1;
     94         str2+=str2;
     95         SuffixArray sa1(str1.c_str());
     96         int pos1;
     97         for(int i=sa1.n-1; i>=1; --i) {
     98             if(sa1.sa[i]<n) {
     99                 pos1=sa1.sa[i]; break;
    100             }
    101         }
    102         SuffixArray sa2(str2.c_str());
    103         int pos2=-1, mi=n;
    104         for(int i=sa2.n-1; i>=1; --i) {
    105             if(pos2!=-1) mi=min(mi, sa2.height[i+1]);
    106             if(mi<n) break;
    107             if(sa2.sa[i]<n) pos2=sa2.sa[i];
    108         }
    109         if(cmp(str1, str2, pos1, pos2)) {
    110             printf("%d 0
    ", pos1+1);    
    111         } else {
    112             printf("%d 1
    ", n-pos2);
    113         }
    114     }
    115     return 0;
    116 }
    View Code
  • 相关阅读:
    每天都感觉很疲劳
    如果你决定要自己营销
    昨天忘记写日记了,今天补充一下!
    终于不用再去北仑了
    良好的程序架构
    最近的天气反复无常
    就这么着
    C# Socket 入门3 UPD
    让程序只启动一次 Mutex
    C# Socket 入门2
  • 原文地址:https://www.cnblogs.com/shjwudp/p/4814172.html
Copyright © 2020-2023  润新知