【CodeForces 261D】Maxim and Increasing Subsequence

链接:

洛谷

博客园

题目大意:

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

正文:

如果 \(t\) 足够大,答案是固定的。设 \(cnt\) 表示 \(b\) 数组不同数字个数,则显然有当 \(cnt\leq 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\n", 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\n", ans);
	}
    return 0;
}
posted @ 2021-01-23 11:49  Jayun  阅读(83)  评论(0编辑  收藏  举报