zoukankan      html  css  js  c++  java
  • poj 1509

    求一个字符串在旋转置换群下最小字典表示。

    用的是后缀数组(后缀自动机还是再听听jason_yu讲讲吧,关于right集合的部分还有问题)

    最小表示法的思想很有好(判断两个对象在某一置换群划分下,是否等价,可以求出两个对象在该置换群划分下的最小表示,然后比较最小表示)

     1 #include <cstdio>
     2 #include <cstring>
     3 #define min(a,b) ((a)<(b)?(a):(b))
     4 #define N 20010
     5 
     6 int n, aa[N];
     7 int sa[N], rk[N], ht[N], vv[N];
     8 
     9 void expand( int *s, int *r, int *sa, int *rk, int k ) {
    10     for( int i=1; i<=n; i++ )
    11         vv[r[s[i]]]=i;
    12     for( int i=n; i>=1; i-- )
    13         if( s[i]>k ) sa[vv[r[s[i]-k]]--] = s[i]-k;
    14     for( int i=n-k+1; i<=n; i++ )
    15         sa[vv[r[i]]--] = i;
    16     for( int i=1; i<=n; i++ )
    17         rk[sa[i]] = rk[sa[i-1]]+(r[sa[i]]!=r[sa[i-1]]||r[sa[i]+k]!=r[sa[i-1]+k]);
    18 }
    19 void calcht() {
    20     for( int i=1,k=0; i<=n; i++ ) {
    21         if( rk[i]==1 ) {
    22             k = ht[i] = 0;
    23             continue;
    24         }
    25         int j=sa[rk[i]-1];
    26         while( aa[i+k]==aa[j+k] ) k++;
    27         ht[i] = k;
    28         if( k>0 ) k--;
    29     }
    30 }
    31 void suffix() {
    32     static int tsa[N], trk[N];
    33     for( int i=1; i<=26; i++ ) vv[i] = 0;
    34     for( int i=1; i<=n; i++ ) vv[aa[i]]++;
    35     for( int i=1; i<=26; i++ ) vv[i]+=vv[i-1];
    36     for( int i=n; i>=1; i-- ) sa[vv[aa[i]]--]=i;
    37     for( int i=1; i<=n; i++ )
    38         rk[sa[i]] = rk[sa[i-1]]+(aa[sa[i]]!=aa[sa[i-1]]);
    39     for( int k=1; k<n; k<<=1 ) {
    40         expand( sa, rk, tsa, trk, k );
    41         for( int i=1; i<=n; i++ )
    42             sa[i]=tsa[i], rk[i]=trk[i];
    43     }
    44     calcht();
    45 }
    46 int sov() {
    47     int nn = (n+1)>>1;
    48     for( int i=1; i<=n; i++ )
    49         if( n-sa[i]+1>=nn ) {
    50             int rt = sa[i];
    51             for( int j=i+1; j<=n && ht[sa[j]]>=nn; j++ ) 
    52                 rt = min( rt, sa[j] );
    53             return rt;
    54         }
    55     return -1;
    56 }
    57 int main() {
    58     int T;
    59     scanf( "%d", &T );
    60     while( T-- ) {
    61         static char buf[N];
    62         scanf( "%s", buf+1 );
    63         n = strlen( buf+1 );
    64         for( int i=1; i<=n; i++ )
    65             aa[i+n] = aa[i] = buf[i]-'a'+1;
    66         n += n;
    67         suffix();
    68         printf( "%d
    ", sov() );
    69     }
    70 }
    View Code
  • 相关阅读:
    C#开发规范
    Win32API使用技巧 -- 置顶应用
    Windows开发常用快捷键
    MarkDown简单语法回顾
    样本分布
    复变函数
    set theory
    Oscar的数理统计笔记本
    Oscar的拓扑笔记本
    c语言总结
  • 原文地址:https://www.cnblogs.com/idy002/p/4449513.html
Copyright © 2011-2022 走看看