PKU 3617和PKU 3623是一样的题,只是数据范围不同。
3617是2000个字符,而3623是30000个字符。只是3623的时限比较松,贪心也可以过。
本题有两种解法,分别是贪心O(n^2)和后缀数组O(nlogn)
后缀数组法:
贪心法:
3617是2000个字符,而3623是30000个字符。只是3623的时限比较松,贪心也可以过。
本题有两种解法,分别是贪心O(n^2)和后缀数组O(nlogn)
后缀数组法:
- /*
- Title: Best Cow Line
- Author: Jeff
- Time: 2008/10/30
- Complexity: O(Nlog(N));
- Result: 2256K 766MS/ AC
- Reference:
- Description:
- 给定一个字符数组,可以从数组的开头或者结尾取出元素,
- 按取出顺序排成一列,使得他的字典序最小。
- Tips:
- 后缀数组
- 将原字符数组和字符数组的逆序合在一次进行后缀数组排序,
- 然后对rank数组前N和后N个数进行比较,哪个小就输出相应的
- 字符值,同时对应的下标++,直到输出N个字符为止。
- p.s.
- 注意题目要求每一行输出80个字符。
- */
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int MAX = 30000;
- struct Sfx{
- int idx;
- int key[2];
- bool operator<(const Sfx &other)const{
- return key[0] < other.key[0] ||
- key[0] == other.key[0] && key[1] < other.key[1];
- }
- };
- char cow[MAX * 2];
- Sfx sa[MAX * 2], temp_sa[MAX * 2];
- int rank[MAX * 2];
- int cnt[MAX * 2];
- void cSort(Sfx *in, int key, int len, Sfx *out){
- memset(cnt, 0, sizeof(cnt));
- for(int i = 0; i < len; i++)cnt[ in[i].key[key] ]++;
- for(int i = 1; i < len; i++)cnt[i] += cnt[i - 1];
- for(int i = len - 1; i >= 0; i--)
- out[ --cnt[in[i].key[key]] ] = in[i];
- }
- void build_sfx(int len){
- for(int i = 0; i < len; i++){
- sa[i].idx = i;
- sa[i].key[0] = cow[i];
- sa[i].key[1] = i;
- }
- sort(sa, sa + len);
- for(int i = 0; i < len; i++)sa[i].key[1] = 0;
- int wid = 1;
- while(wid < len){
- rank[sa[0].idx] = 0;
- for(int i = 1; i < len; i++){
- rank[sa[i].idx] = rank[sa[i-1].idx];
- if(sa[i-1] < sa[i])rank[sa[i].idx]++;
- }
- for(int i = 0; i < len; i++){
- sa[i].idx = i;
- sa[i].key[0] = rank[i];
- sa[i].key[1] = i + wid < len ? rank[i + wid] : 0;
- }
- cSort(sa, 1, len, temp_sa); cSort(temp_sa, 0, len, sa);
- wid *= 2;
- }
- }
- int main(){
- freopen("in.txt", "r", stdin);
- freopen("out.txt", "w", stdout);
- int N;
- while(scanf("%d", &N) != EOF){
- int i, j, count;
- for(i = 0; i < N; i++)scanf("%s", cow+i);
- for(i = 0; i < N; i++)cow[2 * N - 1 - i] = cow[i];
- build_sfx(N * 2);
- for(i = 0, j = N, count = 0; i + j < 2 * N - 1; count++){
- if(rank[i] < rank[j]){
- printf("%c", cow[i]);
- i++;
- }
- else{
- printf("%c", cow[j]);
- j++;
- }
- if(count % 80 == 79)printf("/n");
- }
- printf("%c/n", cow[i]);
- }
- return 0;
- }
贪心法:
- /*
- Title: Best Cow Line
- Author: Jeff
- Time: 2008/10/30
- Complexity: O(N^2);
- Result: 344K 2235MS/ AC
- Reference:
- Description:
- 给定一个字符数组,可以从数组的开头或者结尾取出元素,
- 按取出顺序排成一列,使得他的字典序最小。
- Tips:
- 贪心
- p.s.
- */
- #include <cstdio>
- #include <cstring>
- using namespace std;
- const int MAX = 30000;
- char cow[MAX+1];
- int main(){
- freopen("in.txt", "r", stdin);
- freopen("out.txt", "w", stdout);
- int N;
- while(scanf("%d", &N) != EOF){
- int i, j, count;
- for(i = 0; i < N; i++)scanf("%s", cow+i);
- for(i = 0, j = N-1, count = 0; i < j; count++){
- int ii, jj;
- for(ii = i, jj = j; ii <= j; ii++, jj--){
- if(cow[ii] > cow[jj]){
- printf("%c", cow[j]);
- j--;
- break;
- }
- else if(cow[ii] < cow[jj]){
- printf("%c", cow[i]);
- i++;
- break;
- }
- }
- if(ii > j){
- printf("%c", cow[i]);
- i++;
- }
- if(count % 80 == 79)printf("/n");
- }
- printf("%c/n", cow[i]);
- }
- return 0;
- }