导弹拦截
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都要高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹,同时,司令部想知道拦截下来的导弹的高度。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。
Input
第一行是一个整数 t ,代表case数。 对于每一个case,第一行是一个整数 n(1≤n≤100000) ; 第二行是 n 个正整数,表示第 n 枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。数据保证高度不会超过 100000 .
Output
对于每一个case,第一行输出最多能拦截的导弹数,第二行按来袭顺序输出拦截下来的导弹的高度构成的序列,以一个空格隔开。若有不止一种方法可以拦截最多的导弹,输出字典序最小的。
Sample input and output
Sample Input | Sample Output |
---|---|
1 5 1 6 3 5 7 | 4 1 3 5 7 |
显然,最长上升子序列。不会求请去学,推荐《算法入门经典训练指南 》(刘汝佳著)在动态规划章节里有
但此题还要求输出字典序最小怎么办呢?
可以证明,从后往前找,每次找到一个d[i]符合要求,并且其值小于last的,就一定是字典序最小的
为什么?
设a[i]表示第i个数在原数列中是多少,d[i]表示以i结尾时候最长上升子序列的长度是多少,g[i]的含义请看刘汝佳那本书
假设i<j 如果 a[i]<a[j] 那么 一定有d[i]<d[j]
所以,如果i<j 且 d[i]==d[j] 那么 a[i]==a[j] 或者 a[i]>a[j]
当a[i]==a[j]的时候,对于a[i]前面待加入答案的值,和a[j]来说是等价的,因为a[i]==a[j] 不妨取越靠后的越好
如果a[i]>a[j],请注意,此时d[i]==d[j],那么,假设选取a[i]的那一个序列,找到了一个最长上升子序列,这个子序列的字典序一定是
大于含有a[j]的那一个序列的。因为d[i]==d[j]所以含有a[i]的那个序列小于d[i]的答案都可以放在含有a[j]的那个序列中,又a[i]>a[j]
所以a[j]的字典序一定更小
由此就可以知道,当跑完一发LIS后,只需要从数列从后往前找,找到一个希望的d[i],并且a[i]<last(last表示序列中后一个的值,这个值已经找到)
那么,i 这个位置就是字典序最小的最长上升子序列的其中一个
//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi 3.1415926535898
#define eps 1e-6
#define MOD 10007
#define MAXN 100100
#define N 10100
#define M
int a[MAXN],g[MAXN],d[MAXN],ans[MAXN];
int n;
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d",&n);
repin(i,1,n)
{
scanf("%d",a+i);
g[i]=INT;
}
int k,maxi=1;
repin(i,1,n)
{
k=(int)(lower_bound(g+1,g+1+n,a[i])-g);
g[k]=a[i];
d[i]=k;
maxi=max(maxi,d[i]);
}
int last=INT,t=maxi;
depin(i,n,1)
{
if(!t) break;
if(d[i]==t && a[i]<last)
{
last=a[i];
ans[t]=a[i];
t--;
}
}
printf("%d\n",maxi);
bool first=true;
repin(i,1,maxi)
{
if(first) first=false;
else printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
}