题目大意
起初给你n的排列,然后给你一个序列b,b[i]表示第i轮位置为b[i]的数可用,问每一轮可用的数列形成的LIS(最长上升子序列)为多少。
LIS
推荐一篇特别详细特别用心的博客:
戳最长上升子序列 (LIS) 详解+例题模板 (全)
LIS的两种nlogn的方法都需要掌握,但是常用的是贪心+二分的这种,树状数组思想比写法重要,要善于灵活应用,特别是很类似于离散化然后添点形成大小关系从而求出某种序列的时候,要想到类比LIS的树状数组做法。
官方题解
考虑时间倒流,一开始先求出整个排列的LIS
然后考虑删点
如果删的点不在LIS中,那么我们当前轮次的LIS就是上一轮次的LIS
否则删的点在LIS中,那么我们就需要重新求一遍LIS,这里有点暴力的意思,但是由于数据随机生成,所以在LIS中的点大概有根号n个,所以其实不会超时
这里涉及到一个点是记录LIS的路径,代码中有所体现,可以当成板子背一下,其实和dp记录路径的思想是一样的,先求完然后倒推回来。
总时间复杂度 O(n * sqrt(n) * logn),14s的时间…
//#include <bits/stdc++.h>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <utility>
#include <assert.h>
#define endl '\n'
#define p_b push_back
#define e_b emplace_back
#define debug cout<<"!!!"<<endl;
//#define LOCAL
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const static int inf = 0x3f3f3f3f;
const static ll infll = 0x3f3f3f3f3f3f3f3f;
const static int maxn = 5e4+10;
int n;
int a[maxn], b[maxn];
bool froze[maxn];
bool used[maxn];
int res[maxn];
int path[maxn];
int li[maxn];
int lis()
{
memset(path, 0, sizeof path);
int ret = 0;
for(int i=1; i<=n; i++)
{
if(froze[a[i]])
continue;
//这里尽量这样写,更合理一些,li数组是下标为0开始存放贪心得到的序列
int pos = lower_bound(li, li+ret, a[i]) - li;
if(pos == ret)
{
li[ret++] = a[i];
path[i] = ret;
}
else
{
path[i] = pos+1;//加1是下标偏移
li[pos] = a[i];
}
}
memset(used, false, sizeof used);
int tmp = ret;
for(int i=n; i>=1; i--)
{
if(froze[a[i]])
continue;
if(path[i] == tmp)
{
used[a[i]] = true;
tmp--;
}
}
return ret;
}
int main()
{
#ifdef Local
freopen("1002.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int t;
scanf("%d", &t);
while(t--)
{
memset(froze, false, sizeof froze);
memset(res, 0, sizeof res);
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) scanf("%d", &b[i]);
res[n] = lis();
//cout<<res[n]<<endl;
//debug;
froze[a[b[n]]] = true;
for(int i=n-1; i>=1; i--)
{
if(!used[a[b[i+1]]])
res[i] = res[i+1];
else
res[i] = lis();
froze[a[b[i]]] = true;
}
for(int i=1; i<=n; i++)
{
if(i == 1)
printf("%d", res[i]);
else
printf(" %d", res[i]);
}
printf("\n");
}
return 0;
}