bzoj 1692: [Usaco2007 Dec]队列变换

把序列(串)反过来,连到原串上,然后求一下后缀数组,答案就是每次比较a1,a2(a1初始为1,a2初始为n+1),输出rank小的一个

 1 #include<bits/stdc++.h>
 2 #define N 100005<<1
 3 #define LL long long
 4 #define inf 0x3f3f3f3f
 5 using namespace std;
 6 inline int ra()
 7 {
 8     int x=0,f=1; char ch=getchar();
 9     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
10     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
11     return x*f;
12 }
13 int p,q,k,n,a[N],v[N],rank[2][N],sa[2][N];
14 void cal_sa(int sa[N], int rank[N], int Sa[N], int Rank[N])
15 {
16     for (int i=1; i<=n; i++) v[rank[sa[i]]]=i;
17     for (int i=n; i>=1; i--)
18         if (sa[i]>k)
19             Sa[v[rank[sa[i]-k]]--]=sa[i]-k;
20     for (int i=n-k+1; i<=n; i++)
21         Sa[v[rank[i]]--]=i;
22     for (int i=1; i<=n; i++)
23         Rank[Sa[i]]=Rank[Sa[i-1]]+(rank[Sa[i-1]]!=rank[Sa[i]] || rank[Sa[i-1]+k]!=rank[Sa[i]+k]);
24 }
25 void work()
26 {
27     p=0,q=1; 
28     for (int i=1; i<=n; i++) v[a[i]]++;
29     for (int i=1; i<=30; i++) v[i]+=v[i-1];
30     for (int i=1; i<=n; i++) sa[p][v[a[i]]--]=i;
31     for (int i=1; i<=n; i++) rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
32     for (k=1; k<n; k<<=1,q^=1,p^=1) cal_sa(sa[p],rank[p],sa[q],rank[q]);
33 }
34 int main()
35 {
36     n=ra();
37     for (int i=1; i<=n; i++)
38     {
39         char ch[2]; scanf("%s",ch);
40         a[i]=ch[0]-'A'+1;
41         a[n-i+1+n]=a[i];
42     }
43     n<<=1;
44     work();
45     int a1=1,a2=n/2+1;
46     for (int i=1; i<=n>>1; i++)
47     {
48         if (rank[p][a1]<rank[p][a2]) printf("%c",(char)a[a1++]+'A'-1);
49             else printf("%c",(char)a[a2++]+'A'-1);
50         if (!(i%80)) cout<<endl;
51     }
52     return 0;
53 }

 

posted @ 2017-02-27 21:29  ws_ccd  阅读(165)  评论(0编辑  收藏  举报