一道最长上升子序列的裸题
由题目描述可以看出,我们选择的日期中每天做题数量一定是递增的。这样,我们就能很轻易地想到用最长上升子序列去完成这道题。在这里,由于数据范围较大,我们需要用nlogn的算法去完成这道题。
那么,怎么去处理这必须做题的k天呢?
由于这k天做题数量一定是最长上升子序列的一部分,这样我们就可以发现有某些天是一定不能选的。当我们把这些一定不能选的日期删掉后就会发现,只要我们按照正常的算法去求最长上升子序列,那么这k天一定是包含在里面的。(想一想,为什么)
至于判断是否有最长上升子序列,只需要判读这必选的k天是否单调上升即可。
附一下代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,k,cnt,t,a[500005],c[250005],sta[500005];
int mysort(int a,int b) {return a < b;}
int judge()
{
sort(c + 1, c + k + 1, mysort);
for(int i = 2; i <= k; i++)
if(a[c[i]] <= a[c[i - 1]])
{
printf(“impossible”);
return 1;
}
return 0;
}
void clean()
{
for(int i = 1; i < c[1]; i++)
if(a[i] >= a[c[1]])
a[i] = -1;
for(int i = 1; i < k; i++)
for(int j = c[i] + 1; j <= c[i + 1] - 1; j++)
if(a[j] <= a[c[i]] || a[j] >= a[c[i + 1]])
a[j] = -1;
for(int i = c[k] + 1; i <= n; i++)
if(a[i] <= a[c[k]])
a[i] = -1;
for(int i = 1; i <= n; i++)
if(a[i] != -1)
a[++cnt] = a[i];
}
void two_fen(int k)
{
int l = 1,r = t,mid;
while(l <= r)
{
mid = (l + r) >> 1;
if(sta[mid] < k) l = mid + 1;
else r = mid - 1;
}
sta[l] = k;
}
void work()
{
sta[0] = -1008611;
for(int i = 1; i <= cnt; i++)
{
if(a[i] > sta[t]) sta[++t] = a[i];
else two_fen(a[i]);
}
printf(“%d\n”,t);
}
int main()
{
scanf(“%d%d”,&n,&k);
for(int i = 1; i <= k; i++) scanf(“%d”,&c[i]);
for(int i = 1; i <= n; i++) scanf(“%d”,&a[i]);
if(judge()) return 0;
clean();
work();
return 0;
}