PKU 3617 Best Cow Line和PKU 3623 Best Cow Line 解题报告

PKU 3617和PKU 3623是一样的题,只是数据范围不同。
3617是2000个字符,而3623是30000个字符。只是3623的时限比较松,贪心也可以过。

本题有两种解法,分别是贪心O(n^2)和后缀数组O(nlogn)

后缀数组法:

  1. /*
  2.   Title: Best Cow Line
  3.   Author: Jeff
  4.   Time:  2008/10/30
  5.   Complexity: O(Nlog(N));
  6.   Result: 2256K 766MS/ AC
  7.   Reference: 
  8.         
  9.   Description: 
  10.         给定一个字符数组,可以从数组的开头或者结尾取出元素,
  11.         按取出顺序排成一列,使得他的字典序最小。
  12.   Tips:
  13.         后缀数组 
  14.         将原字符数组和字符数组的逆序合在一次进行后缀数组排序,
  15.         然后对rank数组前N和后N个数进行比较,哪个小就输出相应的
  16.         字符值,同时对应的下标++,直到输出N个字符为止。  
  17.         
  18.   p.s. 
  19.         注意题目要求每一行输出80个字符。 
  20. */
  21. #include <cstdio>
  22. #include <cstring>
  23. #include <algorithm>
  24. using namespace std;
  25. const int MAX = 30000;
  26. struct Sfx{
  27.     int idx;
  28.     int key[2];
  29.     bool operator<(const Sfx &other)const{
  30.         return key[0] < other.key[0] || 
  31.             key[0] == other.key[0] && key[1] < other.key[1];    
  32.     }    
  33. };
  34. char cow[MAX * 2];
  35. Sfx sa[MAX * 2], temp_sa[MAX * 2];
  36. int rank[MAX * 2];
  37. int cnt[MAX * 2];
  38. void cSort(Sfx *in, int key, int len, Sfx *out){
  39.     memset(cnt, 0, sizeof(cnt));
  40.     for(int i = 0; i < len; i++)cnt[ in[i].key[key] ]++;
  41.     for(int i = 1; i < len; i++)cnt[i] += cnt[i - 1];
  42.     for(int i = len - 1; i >= 0; i--)
  43.         out[ --cnt[in[i].key[key]] ] = in[i];
  44. }
  45. void build_sfx(int len){
  46.     for(int i = 0; i < len; i++){
  47.         sa[i].idx = i;
  48.         sa[i].key[0] = cow[i];
  49.         sa[i].key[1] = i;
  50.     }
  51.     sort(sa, sa + len);
  52.     
  53.     for(int i = 0; i < len; i++)sa[i].key[1] = 0;
  54.     
  55.     int wid = 1;
  56.     while(wid < len){
  57.         rank[sa[0].idx] = 0;
  58.         for(int i = 1; i < len; i++){
  59.             rank[sa[i].idx] = rank[sa[i-1].idx];   
  60.             if(sa[i-1] < sa[i])rank[sa[i].idx]++;
  61.         }
  62.         for(int i = 0; i < len; i++){
  63.             sa[i].idx = i;
  64.             sa[i].key[0] = rank[i];
  65.             sa[i].key[1] = i + wid < len ? rank[i + wid] : 0;    
  66.         }
  67.         cSort(sa, 1, len, temp_sa); cSort(temp_sa, 0, len, sa);
  68.         wid *= 2;
  69.     }
  70. }
  71. int main(){
  72.     freopen("in.txt""r", stdin);
  73.     freopen("out.txt""w", stdout);
  74.     int N;
  75.     while(scanf("%d", &N) != EOF){
  76.         int i, j, count;
  77.         for(i = 0; i < N; i++)scanf("%s", cow+i);
  78.         for(i = 0; i < N; i++)cow[2 * N - 1 - i] = cow[i];
  79.         build_sfx(N * 2);
  80.             
  81.         for(i = 0, j = N, count = 0; i + j < 2 * N - 1; count++){
  82.             if(rank[i] < rank[j]){
  83.                 printf("%c", cow[i]);
  84.                 i++;
  85.             }
  86.             else{
  87.                 printf("%c", cow[j]);
  88.                 j++;
  89.             }
  90.             if(count % 80 == 79)printf("/n");
  91.         }
  92.         printf("%c/n", cow[i]);
  93.     }
  94.     return 0;    
  95. }



贪心法:
  1. /*
  2.   Title: Best Cow Line
  3.   Author: Jeff
  4.   Time:  2008/10/30
  5.   Complexity: O(N^2);
  6.   Result: 344K  2235MS/ AC
  7.   Reference: 
  8.         
  9.   Description: 
  10.         给定一个字符数组,可以从数组的开头或者结尾取出元素,
  11.         按取出顺序排成一列,使得他的字典序最小。
  12.   Tips:
  13.         贪心 
  14.   p.s. 
  15. */
  16. #include <cstdio>
  17. #include <cstring>
  18. using namespace std;
  19. const int MAX = 30000;
  20. char cow[MAX+1];
  21. int main(){
  22.     freopen("in.txt""r", stdin);
  23.     freopen("out.txt""w", stdout);
  24.     int N;
  25.     while(scanf("%d", &N) != EOF){
  26.         int i, j, count;
  27.         for(i = 0; i < N; i++)scanf("%s", cow+i);
  28.         for(i = 0, j = N-1, count = 0; i < j; count++){
  29.             int ii, jj;
  30.             for(ii = i, jj = j; ii <= j; ii++, jj--){
  31.                 if(cow[ii] > cow[jj]){
  32.                     printf("%c", cow[j]);
  33.                     j--;
  34.                     break;
  35.                 }
  36.                 else if(cow[ii] < cow[jj]){
  37.                     printf("%c", cow[i]);
  38.                     i++;
  39.                     break;    
  40.                 }
  41.             }
  42.             if(ii > j){
  43.                 printf("%c", cow[i]);    
  44.                 i++;
  45.             }
  46.             if(count % 80 == 79)printf("/n");
  47.         }
  48.         printf("%c/n", cow[i]);
  49.     }
  50.     return 0;    
  51. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值