题意:
链接:HDU - 6635
给你 n 不同的且属于 [1, n] 的数列 p,然后在给你 n 个数 k1 - kn,代表 n 次操作,开始数列是被冻住的只有解冻的数才可以使用,按照给的n次操作,每次操作解冻一个位置,并输出当前所有被解冻的数的最长上升子序列的长度。
解题思路:
有句非常关键的语句:It is guaranteed that p1,p2,...,pn and k1,k2,...,kn are generated randomly。所以我们倒着求,把解冻换成冰冻,每冰冻一个在ki位置的数,判断是否在当前最长上升子序列里面,如果不在直接输出当前的最长上升子序列的长度,否则重新计算最长上升子序列,因为数据是随机给出的,求最长上升子序列的次数的期望是只有 √n 次的,每次计算是 nlogn ,总的时间复杂度为: n√nlogn。其中需要标记最长上升子序列的路径以便于判断冰冻的元素是都是在当前的最长上升子序列里面。
这代码写的有点太丑,主要这个题目的思想很好,下次要记住这个随机生成,其实就表明他不会有特殊样例来卡你。
AC代码:
#include<bits/stdc++.h>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
using namespace std;
int n, len, cur_ans;
int a[maxn], del[maxn], dp[maxn];
int vis[maxn], pre[maxn], ans[maxn];
list<int> lst;
list<int> :: iterator iter;
int solve(int x)
{
if(x == -1)
{
for(int i = 1; i <= n; i++) pre[i] = i;
int k = 1;
dp[k] = *lst.begin();
iter = lst.begin();
for(++iter; iter != lst.end(); iter++)
{
if(dp[k] < *iter)
{
pre[*iter] = dp[k];
dp[++k] = *iter;
}
else
{
int loc = lower_bound(dp + 1, dp + 1 + k, *iter) - dp;
if(loc > 1)
{
pre[*iter] = dp[loc - 1];
}
dp[loc] = *iter;
}
}
memset(vis, 0, sizeof(vis));
int x = dp[k]; vis[x] = 1;
while(x != pre[x])
{
x = pre[x];
vis[x] = 1;
}
return cur_ans = k;
}
if(vis[ a[x] ] == 0)
{
iter = lst.begin();
while(iter != lst.end())
{
if(*iter == a[x])
{
lst.erase(iter);
break;
}++iter;
}
return cur_ans;
}
else
{
for(int i = 1; i <= n; i++) pre[i] = i;
iter = lst.begin();
while(iter != lst.end())
{
if(*iter == a[x])
{
lst.erase(iter);
break;
}++iter;
}
int k = 1;
iter = lst.begin();
dp[k] = *iter;
for(++iter; iter != lst.end(); iter++)
{
if(dp[k] < *iter)
{
pre[*iter] = dp[k];
dp[++k] = *iter;
}
else
{
int loc = lower_bound(dp + 1, dp + 1 + k, *iter) - dp;
if(loc > 1)
{
pre[*iter] = dp[loc - 1];
}
dp[loc] = *iter;
}
}
memset(vis, 0, sizeof(vis));
int x = dp[k]; vis[x] = 1;
while(x != pre[x])
{
x = pre[x];
vis[x] = 1;
}
return cur_ans = k;
}
}
int main()
{
int T; scanf("%d", &T); while(T--)
{
lst.clear();
len = 0;
scanf("%d", &n);
up(i, 1, n) scanf("%d", &a[i]), lst.push_back(a[i]);
up(i, 1, n) scanf("%d", &del[i]);
ans[n] = solve(-1);
for(int i = n; i > 1; i--)
{
ans[i - 1] = solve(del[i]);
}
for(int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
}