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\n", sov() );
69     }
70 }
View Code

 

posted @ 2015-04-23 10:01  idy002  阅读(161)  评论(0编辑  收藏  举报