链接:
题目大意:
将长度为 (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;
}