HDU 2890 Longest Repeated subsequence

Description

Write a program that takes a sequence of number and returns length of the longest repeated 
subsequence. A repeated subsequence which repeats identically at least K times without overlaps. 
For example 1 2 3 1 2 3 2 3 1 repeats 2 3 for three times. 

Input

Line 1: The input contains a single integer T , the number of test cases. 
Line 2: Two space-separated integers: N and K (1 <= n <= 50000), (2 <= k <= n) 
Lines 3..N+2: N integers, one per line. The integer is between 0 and 10^9. 
It is guaranteed that at least one subsequence is repeated at least K times. 

Output

For each test case, the first line print the length n of the Longest Repeated Subsequence and the line 2…n+1 print the subsequence numbers.(if we have several subsequence with the same length output the lexicographic order smallest one). Separate output for adjacent cases with a single blank line.

Sample Input

1
8 2
1
2
3
2
3
2
3
1

Sample Output

2
2

3

后缀数组,二分长度+验证。

#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 = 3e5 + 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;
}
int T, cas = 0;

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

	bool GetS()
	{
		scanf("%d%d", &n, &K);
		rep(i, 1, n) scanf("%d", &a[i]), s[i] = a[i];
		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]]);
	}
	*/

	bool check(int x, int &y)
	{
		int tot = 0;
		b[tot++] = sa[1];
		for (int i = 2; i <= n + 1; i++)
		{
			if (i <= n&&h[i] >= x) b[tot++] = sa[i];
			else
			{
				sort(b, b + tot);
				int now = -INF, cnt = 0;
				rep(k, 0, tot - 1) if (b[k] >= now + x) now = b[k], cnt++;
				if (cnt >= K) { y = sa[i - 1]; return true; }
				tot = 0; b[tot++] = sa[i];
			}
		}
		return false;
	}

	void work()
	{
		GetS();	getsa(m);
		int l = 1, r = n, g;
		while (l <= r)
		{
			if (check(l + r >> 1, g)) l = (l + r >> 1) + 1;
			else r = (l + r >> 1) - 1;
		}
		check(r, g);
		printf("%d\n", r);
		rep(i, 1, r) printf("%d\n", a[s[g + i - 1]]);
	}
}sa;

int main()
{
	T = read(); 
	while (T--)
	{
		sa.work();
		if (T) printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值