zoukankan      html  css  js  c++  java
  • 1692. [USACO07DEC] 队列变换【后缀数组+贪心】

    Description

    FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”。在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席前依次走过。 今年,竞赛委员会在接受队伍报名时,采用了一种新的登记规则:他们把所有队伍中奶牛名字的首字母取出,按它们对应奶牛在队伍中的次序排成一列(比如说,如果FJ带去的奶牛依次为Bessie、Sylvia、Dora,登记人员就把这支队伍登记为BSD)。登记结束后,组委会将所有队伍的登记名称按字典序升序排列,就得到了他们的出场顺序。 FJ最近有一大堆事情,因此他不打算在这个比赛上浪费过多的时间,也就是说,他想尽可能早地出场。于是,他打算把奶牛们预先设计好的队型重新调整一下。 FJ的调整方法是这样的:每次,他在原来队列的首端或是尾端牵出一头奶牛,把她安排到新队列的尾部,然后对剩余的奶牛队列重复以上的操作,直到所有奶牛都被插到了新的队列里。这样得到的队列,就是FJ拉去登记的最终的奶牛队列。 接下来的事情就交给你了:对于给定的奶牛们的初始位置,计算出按照FJ的调整规则所可能得到的字典序最小的队列。

    Input

    * 第1行: 一个整数:N

    * 第2..N+1行: 第i+1行仅有1个'A'..'Z'中的字母,表示队列中从前往后数第i 头奶牛名字的首字母

    Output

    * 第1..??行: 输出FJ所能得到的字典序最小的队列。每行(除了最后一行)输 出恰好80个'A'..'Z'中的字母,表示新队列中每头奶牛姓名的首 字母

    Sample Input

    6
    A
    C
    D
    B
    C
    B

    输入说明:

    FJ有6头顺次排好队的奶牛:ACDBCB

    Sample Output

    ABCBCD

    输出说明:

    操作数 原队列 新队列
    #1 ACDBCB
    #2 CDBCB A
    #3 CDBC AB
    #4 CDB ABC
    #5 CD ABCB
    #6 D ABCBC
    #7 ABCBCD

    贪心+后缀数组
    正str+0+反str  构建一个字符串求SA
    指针i,j分别指正反两个字符串的最左边(相当于从头和从尾开始取)
    两个指针位置取小的,若相等则取后缀字典序小的
    贪心证明并不是很会,在网上找了半天也只有一个还不错:
     
    显然如果f[L]>g[R]的话,那么假如 s[L + 0..p ] == s[R - 0..p] 相等,
    下一s[L + p + 1] > s[R - p -1]一定会不相等,并且s[R-p-1]更优,
    如果完全相等那么说明怎么取都一样。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define MAXN (70000+10)
     5 using namespace std;
     6 int wa[MAXN],wb[MAXN],wt[MAXN];
     7 int Height[MAXN],SA[MAXN],Rank[MAXN];
     8 char r[MAXN];
     9 int n,m=130,k; 
    10 
    11 bool cmp(int *y,int a,int b,int k)
    12 {
    13     int arank1=y[a];
    14     int brank1=y[b];
    15     int arank2=a+k>=n?-1:y[a+k];
    16     int brank2=b+k>=n?-1:y[b+k];
    17     return arank1==brank1 && arank2==brank2;
    18 }
    19 
    20 void Build_SA()
    21 {
    22     int *x=wa,*y=wb;
    23     for (int i=0;i<m;++i) wt[i]=0;
    24     for (int i=0;i<n;++i) wt[x[i]=r[i]]++;
    25     for (int i=1;i<m;++i) wt[i]+=wt[i-1];
    26     for (int i=n-1;i>=0;--i) SA[--wt[x[i]]]=i;
    27     
    28     for (int j=1;j<=n;j<<=1)
    29     {
    30         int p=0;
    31         for (int i=n-j;i<n;++i) y[p++]=i;
    32         for (int i=0;i<n;++i) if (SA[i]>=j) y[p++]=SA[i]-j;
    33         
    34         for (int i=0;i<m;++i) wt[i]=0;
    35         for (int i=0;i<n;++i) wt[x[y[i]]]++;
    36         for (int i=0;i<m;++i) wt[i]+=wt[i-1];
    37         for (int i=n-1;i>=0;--i) SA[--wt[x[y[i]]]]=y[i];
    38         
    39         m=1;swap(x,y);
    40         x[SA[0]]=0;
    41         for (int i=1;i<n;++i)
    42             x[SA[i]]=cmp(y,SA[i],SA[i-1],j)?m-1:m++;
    43         if (m>=n) return;
    44     } 
    45 }
    46 
    47 int main()
    48 {
    49     scanf("%d",&n);
    50     scanf("%s",r);
    51     r[n]='0';
    52     n=n*2+1;
    53     for (int i=(n-1)/2+1;i<n;++i) 
    54         r[i]=r[n-i-1]; 
    55     Build_SA();
    56     for (int i=0;i<n;++i) Rank[SA[i]]=i;
    57     int L=0,R=(n-1)/2+1;
    58     int sum=0;
    59     while (sum<(n-1)/2)
    60     {
    61         if (r[L]==r[R])
    62             Rank[L]<Rank[R]?printf("%c",r[L++]):printf("%c",r[R++]); 
    63         else
    64             r[L]<r[R]?printf("%c",r[L++]):printf("%c",r[R++]); 
    65         ++sum;
    66         if (sum%80==0) printf("
    ");
    67     }
    68 }
  • 相关阅读:
    背水一战 Windows 10 (26)
    背水一战 Windows 10 (25)
    背水一战 Windows 10 (24)
    背水一战 Windows 10 (23)
    背水一战 Windows 10 (22)
    背水一战 Windows 10 (21)
    背水一战 Windows 10 (20)
    背水一战 Windows 10 (19)
    背水一战 Windows 10 (18)
    背水一战 Windows 10 (17)
  • 原文地址:https://www.cnblogs.com/refun/p/8679048.html
Copyright © 2011-2022 走看看