【CodeForces 261D】Maxim and Increasing Subsequence

链接:

洛谷

博客园

题目大意:

将长度为 (n)(b) 数组复制 (t),首尾相连后得到 (a) 数组,求 (a) 的最长上升序列长度。

正文:

如果 (t) 足够大,答案是固定的。设 (cnt) 表示 (b) 数组不同数字个数,则显然有当 (cntleq t) 时答案是 (cnt)

再考虑 (cnt>t) 的情况。跑一趟 (O(n^2t^2)) 的最长上升子序列显然不可能,考虑优化它。设 (f_i) 表示 (a) 数组中第 (i) 个数在最长上升序列的最长长度。则有:

[f_i=max_{j<i,a_j<a_i}{f_i+1} ]

其中 (max) 可以用树状数组维护。

还有一点,空间 (O(nt)) 是接受不了的,考虑滚动数组,滚到 (O(n)) 就行了。

代码:

int k, t, n, maxb, cnt;
bool a[N];

int tr[N], f[N], b[N];

void update(int x, int val)
{
	for (; x <= maxb; x += x & -x) tr[x] = max(tr[x], val);
	return;
}

int query(int x)
{
	int ans = 0;
	for (; x; x -= x & -x) ans = max(ans, tr[x]);
	return ans;
}

int ans;

int main() 
{
    for (scanf("%d%d%d%d", &k, &n, &maxb, &t); k--; )
    {
    	ans = 0;
    	memset (a, 0, sizeof a);
    	memset (b, 0, sizeof b);
    	memset (tr, 0, sizeof tr);
    	memset (f, 0, sizeof f);
    	cnt = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		scanf ("%d", &b[i]);
    		if (!a[b[i]]) cnt++, a[b[i]] = 1;
		}
		if (cnt <= t) {printf ("%d
", cnt); continue;} 
		for (int j = 1; j <= t; j++)
			for (int i = 1; i <= n; i++)
			{
				int tmp = query(b[i] - 1) + 1;
				if (tmp > f[i])
				{
					f[i] = tmp;
					update(b[i], tmp);
					ans = max (ans, tmp);
				}
			}
		printf ("%d
", ans);
	}
    return 0;
}
原文地址:https://www.cnblogs.com/GJY-JURUO/p/14316871.html