您的位置:首页 > 产品设计 > UI/UE

POJ 3581 Sequence

2012-03-10 19:37 302 查看
题目大意:

给N个数(N不超过200000), 保证第一个数比后面的都大, 要求你把数列分成连续的三段, 分别逆序再拼起来, 要求新的串字典序最小.

简要分析:

一个直接的思路是想把最小的一个数作为第一段的末尾, 这样是不是最优的呢? 是的, 因为第一个数比后面的数都大, 于是你把所有的最小的数作为第一段的末尾逆序时, 最大的数之前的部分的字典序肯定不一样. 于是就先把整个序列逆序, 求一个后缀数组, 按i从小到大考虑sa[i], 因为第一个串的长度最多是N - 2, 所以sa[i]必须大于2, 找到最小的i即可.

于是问题转化为, 一个数字串, 分成两段并分别逆序, 使得字典序最小. 假设序列为s, 长度为m, 第一串的末尾为k, 则原来的串s1s2..sk..sk+1sk+2..sm, 在操作后变成了sksk-1..s1smsm-1..sk+1, 注意到这个串是smsm-1sm-2..s1smsm-1sm-2..s1的子串, 于是做法就明了了: 把s逆序并在后面复制一遍, 做一次后缀数组, 找到最小的i, 使得i不超过m, 且要求它大于1(要保证是两个串). 于是时间复杂度O(NlogN), 其实就是后缀数组的复杂度, 我写的倍增啦~

代码实现:

View Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX_N = 200000, MAX_R = MAX_N * 2;
int n, s[MAX_R + 1], sa[MAX_R + 1], rank[MAX_R + 1], height[MAX_R + 1], cnt[MAX_R + 1];
int t[MAX_R + 1], o[MAX_N + 1], m;

struct node_t {
int v[2], p;
bool operator == (const node_t &t) const {
return v[0] == t.v[0] && v[1] == t.v[1];
}
} nd[MAX_R + 1], tp[MAX_R + 1];

int find(int x) {
int l = 1, r = m + 1;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (o[mid] <= x) l = mid;
else r = mid;
}
return l;
}

void ra(int b, int l) {
for (int i = 1; i >= 0; i --) {
memset(cnt, 0, sizeof(int) * (b + 1));
for (int j = 1; j <= l; j ++) cnt[nd[j].v[i]] ++;
for (int j = 1; j <= b; j ++) cnt[j] += cnt[j - 1];
for (int j = l; j >= 1; j --) tp[cnt[nd[j].v[i]] --] = nd[j];
memcpy(nd, tp, sizeof(node_t) * (l + 1));
}
for (int i = 1, j = 1, k = 1; i <= l; i = j, k ++)
while (j <= l && nd[j] == nd[i]) rank[nd[j ++].p] = k;
}

int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &s[i]);
memcpy(o + 1, s + 1, sizeof(int) * n);
sort(o + 1, o + n + 1);
m = unique(o + 1, o + n + 1) - (o + 1);
for (int i = 1; i <= n; i ++) s[i] = find(s[i]);

memcpy(t + 1, s + 1, sizeof(int) * n);
reverse(t + 1, t + n + 1);
for (int i = 1; i <= n; i ++) nd[i].v[0] = t[i], nd[i].v[1] = 0, nd[i].p = i;
ra(m, n);
for (int st = 1; st < n; st <<= 1) {
for (int i = 1; i <= n; i ++) {
nd[i].v[0] = rank[i], nd[i].v[1] = i + st <= n ? rank[i + st] : 0;
nd[i].p = i;
}
ra(n, n);
}
for (int i = 1; i <= n; i ++) sa[rank[i]] = i;

int fir = 1;
while (sa[fir] <= 2) fir ++;
for (int i = sa[fir]; i <= n; i ++) printf("%d\n", o[t[i]]);
memset(t, 0, sizeof(t));
int new_n = sa[fir] - 1;
for (int i = 1; i <= new_n; i ++) t[i] = s[i + n - sa[fir] + 1];
reverse(t + 1, t + new_n + 1);
for (int i = 1; i <= new_n; i ++) t[i + new_n] = t[i];
new_n *= 2;
for (int i = 1; i <= new_n; i ++) nd[i].v[0] = t[i], nd[i].v[1] = 0, nd[i].p = i;
ra(m, new_n);
for (int st = 1; st < new_n; st <<= 1) {
for (int i = 1; i <= new_n; i ++) {
nd[i].v[0] = rank[i], nd[i].v[1] = i + st <= new_n ? rank[i + st] : 0;
nd[i].p = i;
}
ra(new_n, new_n);
}
for (int i = 1; i <= new_n; i ++) sa[rank[i]] = i;
fir = 1;
while (sa[fir] > new_n / 2 || sa[fir] == 1) fir ++;
for (int i = 0; i < new_n / 2; i ++) printf("%d\n", o[t[sa[fir] + i]]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: