POJ 3581 Sequence

原创 2016年08月28日 16:13:39

Description

Given a sequence, {A1A2, ..., An} which is guaranteed AA2, ..., An,  you are to cut it into three sub-sequences and reverse them separately to form a new one which is the smallest possible sequence in alphabet order.

The alphabet order is defined as follows: for two sequence {A1A2, ..., An} and {B1B2, ..., Bn}, we say {A1A2, ..., An} is smaller than {B1B2, ..., Bn} if and only if there exists such i ( 1 ≤ i ≤ n) so that we have Ai < Bi and Aj = Bj for each j < i.

Input

The first line contains n. (n ≤ 200000)

The following n lines contain the sequence.

Output

output n lines which is the smallest possible sequence obtained.

Sample Input

5
10
1
2
3
4

Sample Output

1
10
2
4
3

Hint

{10, 1, 2, 3, 4} -> {10, 1 | 2 | 3, 4} -> {1, 10, 2, 4, 3}


把序列分成非空的三段,每段反转再合并,问字典序最小是多少。

因为A[1]是最大的,所以第一段很简单,求序列反转以后最小的后缀就行了,注意,因为非空,这个后缀不能是第一个或第二个开头的。

然后就是第二段和第三段,在反转的序列中,第二段和第三段就相当于把序列一分为二,位置反过来合并,

这个就是序列的最小表示,可以用最小表示法搞定也可以把序列翻倍再用后缀数组,同样要注意非空的问题。

另外,此题多组数据似乎有问题?

#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define fi first
#define se second
#define mp(i,j) make_pair(i,j)
#define pii pair<string,string>
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e8;
const int N = 5e5 + 10;
const int read()
{
	char ch = getchar();
	while (ch<'0' || ch>'9') ch = getchar();
	int x = ch - '0';
	while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
	return x;
}

struct Sa
{
	int s[N], a[N];
	int rk[2][N], sa[N], h[N], w[N], now, n, m;
	int rmq[N][20], lg[N];

	bool GetS()
	{
		n = read();
		rep(i, 1, n)
		{
			scanf("%d", &s[n - i + 1]);
			a[i] = s[n - i + 1];
		}
		sort(a + 1, a + n + 1);
		m = unique(a + 1, a + n + 1) - a;
		rep(i, 1, n) s[i] = lower_bound(a + 1, a + m, s[i]) - a;
		return true;
	}

	void getsa(int z, int &m)
	{
		int x = now, y = now ^= 1;
		rep(i, 1, z) rk[y][i] = n - i + 1;
		for (int i = 1, j = z; i <= n; i++)
			if (sa[i] > z) rk[y][++j] = sa[i] - z;

		rep(i, 1, m) w[i] = 0;
		rep(i, 1, n) w[rk[x][rk[y][i]]]++;
		rep(i, 1, m) w[i] += w[i - 1];
		per(i, n, 1) sa[w[rk[x][rk[y][i]]]--] = rk[y][i];
		for (int i = m = 1; i <= n; i++)
		{
			int *a = rk[x] + sa[i], *b = rk[x] + sa[i - 1];
			rk[y][sa[i]] = *a == *b&&*(a + z) == *(b + z) ? m - 1 : m++;
		}
	}

	void getsa(int m)
	{
		//n = strlen(s + 1);
		rk[1][0] = now = sa[0] = s[0] = 0;
		rep(i, 1, m) w[i] = 0;
		rep(i, 1, n) w[s[i]]++;
		rep(i, 1, m) rk[1][i] = rk[1][i - 1] + (bool)w[i];
		rep(i, 1, m) w[i] += w[i - 1];
		rep(i, 1, n) rk[0][i] = rk[1][s[i]];
		rep(i, 1, n) sa[w[s[i]]--] = i;

		rk[1][n + 1] = rk[0][n + 1] = 0;	//多组的时候容易出bug
		for (int x = 1, y = rk[1][m]; x <= n && y <= n; x <<= 1) getsa(x, y);
		for (int i = 1, j = 0; i <= n; h[rk[now][i++]] = j ? j-- : j)
		{
			if (rk[now][i] == 1) continue;
			int k = n - max(sa[rk[now][i] - 1], i);
			while (j <= k && s[sa[rk[now][i] - 1] + j] == s[i + j]) ++j;
		}
	}

	void getrmq()
	{
		h[n + 1] = h[1] = lg[1] = 0;
		rep(i, 2, n) rmq[i][0] = h[i], lg[i] = lg[i >> 1] + 1;
		for (int i = 1; (1 << i) <= n; i++)
		{
			rep(j, 2, n)
			{
				if (j + (1 << i) > n + 1) break;
				rmq[j][i] = min(rmq[j][i - 1], rmq[j + (1 << i - 1)][i - 1]);
			}
		}
	}

	int lcp(int x, int y)
	{
		int l = min(rk[now][x], rk[now][y]) + 1, r = max(rk[now][x], rk[now][y]);
		return min(rmq[l][lg[r - l + 1]], rmq[r - (1 << lg[r - l + 1]) + 1][lg[r - l + 1]]);
	}

	void work()
	{
		GetS();	getsa(m);
		rep(i, 1, n) if (sa[i] > 2)
		{ 
			rep(j, sa[i], n) printf("%d\n", a[s[j]]);
			n = sa[i] - 1;
			rep(j, 1, n) s[j + n] = s[j];
			n <<= 1;  getsa(m);
			rep(j, 1, n) if (sa[j] > 1 && sa[j] * 2 <= n)
			{
				rep(k, sa[j], n / 2) printf("%d\n", a[s[k]]);
				rep(k, 1, sa[j] - 1) printf("%d\n", a[s[k]]);
				break;
			}
			break; 
		}
	}
}sa;

int main()
{
	sa.work();
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Poj 3581 Sequence (离散化+后缀数组)

题意:给定一个数列,将其分为非空的三段。然后分别将三段的数字翻转连接在一起组成新的数列。输出处理后字典序最小的结果。 思路:首先注意必须写成单Case的形式!!!while(scanf("%d",&...

poj3581 Sequence (后缀数组)

Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6305   Accepted: 1364 Cas...

POJ3581---Sequence(后缀数组)

DescriptionGiven a sequence, {A1, A2, …, An} which is guaranteed A1 > A2, …, An, you are to cut it ...

poj 3581 Sequence

题目链接:http://poj.org/problem?id=3581 题目大意:求将一个串分成三段再反转后字典序最小。 题目思路:由于题目中说第一个数最大,所以第一切点只要找到最小后缀就可以了,...

POJ3581——Sequence(后缀数组)

白书上的例题,自己敲了一遍,也大概看懂了。 Sequence Time Limit: 5000MS   Memory Limit: 65536K To...

POJ3581——Sequence

1、题意:给一个序列,要求你把它分成三段,每段不能为空,把这三段原位置反转一下,使得字典序最小,求操作后的序列。 2、分析:那个反转好烦人哦,我们把整体序列反转一下,就变成分成三段,然后三段从后向前...

【poj3581】Sequence 后缀数组

DescriptionGiven a sequence, {A1, A2, …, An} which is guaranteed A1 > A2, …, An, you are to cut it ...
  • LOI_DQS
  • LOI_DQS
  • 2016年02月26日 18:41
  • 306

poj 3581

题意:将一个数列分成连续的三段,每段必须有数字,问这三段反转后的数列的最小字典序的方案,并输出,注意:第一个数比后面所有都大 思路:因为第一个数最大,那么将整个数列反转后的字典序最小的后缀为第一段分...

POJ 3581 启发:后缀数组求最小表示

http://poj.org/problem?id=3581 1.第一段是显然的,reverse原数组然后求后缀数组取sa[0]即可……当然要注意每段不能为空这个特点 2.在求第二段的时候就会遇到这道...

POJ 3581 后缀数组

点击打开链接 题意:将一个数列分成连续的三段,每段必须有数字,问这三段反转后的数列的最小字典序的方案,并输出,注意:第一个数比后面所有都大 思路:因为第一个数最大,那么将整个数列反转后的字典序最小...
  • Dan__ge
  • Dan__ge
  • 2016年05月06日 20:14
  • 693
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 3581 Sequence
举报原因:
原因补充:

(最多只允许输入30个字)