题意
A , B A,B A,B两个数组,B[i]表示A中下表为 B [ i ] B[i] B[i]的数字当前可用,求 B [ i ] B[i] B[i]对应的 A A A中的 L I S LIS LIS,其中 A A A中是 [ 1 , n ] [1,n] [1,n]的全排列( r a n d o m _ s u f f l e random\_suffle random_suffle)
思路
- 结论:题解说随机生成, L I S LIS LIS的期望长度 n \sqrt{n} n,删除元素在 L I S LIS LIS中的概率 1 n \frac{1}{\sqrt{n}} n1,所以总的复杂度 O ( n n l o g n ) O(n\sqrt{n}logn) O(nnlogn)
- 倒着处理,判断每次删除的数字在不在当前 L I S LIS LIS中,在就重新求 L I S LIS LIS
- 这个题还需要找出 L I S LIS LIS的路径,这里有个板子
#include <bits/stdc++.h>
const int maxn = 5e4 + 5;
using namespace std;
int a[maxn], b[maxn], c[maxn], d[maxn];
int vis[maxn], used[maxn], path[maxn], n;
int solve() {
int len = 0;
for (int i = 1; i <= n; ++i) {
if (vis[a[i]] == -1) continue;
int it = lower_bound(d, d + len, a[i]) - d;
if (it == len) {
d[len++] = a[i];
path[i] = len;
}else {
d[it] = a[i];
path[i] = it + 1;
}
}
fill(used, used+maxn, 0);
int tmp = len;
for (int i = n; i >= 1; --i) {
if (vis[a[i]] == -1) continue;
if (path[i] == tmp) used[a[i]] = 1, tmp--;
}
return len;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
fill(vis, vis+n+1, 0);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
c[n] = solve();
for (int i = n-1; i >= 1; --i) {
vis[a[b[i+1]]] = -1;
if (used[a[b[i+1]]] == 0) c[i] = c[i+1];
else c[i] = solve();
}
for (int i = 1; i <= n; ++i) {
if (i > 1) printf(" ");
printf("%d", c[i]);
}
puts("");
}
return 0;
}