[NOIP1999 提高组] 导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
一行,若干个整数,中间由空格隔开。
输出格式
两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
样例 #1
样例输入 #1
389 207 155 300 299 170 158 65
样例输出 #1
6
2
提示
对于前
50
%
50\%
50% 数据(NOIP 原题数据),满足导弹的个数不超过
1
0
4
10^4
104 个。该部分数据总分共
100
100
100 分。可使用
O
(
n
2
)
\mathcal O(n^2)
O(n2) 做法通过。
对于后
50
%
50\%
50% 的数据,满足导弹的个数不超过
1
0
5
10^5
105 个。该部分数据总分也为
100
100
100 分。请使用
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn) 做法通过。
对于全部数据,满足导弹的高度为正整数,且不超过 5 × 1 0 4 5\times 10^4 5×104。
此外本题开启 spj,每点两问,按问给分。
NOIP1999 提高组 第一题
LIS和LDS的模板题目
第一问求序列的最长下降序列,第二问求的是原序列的最长不上升子序列
先介绍Dilworth 定理
狄尔沃斯定理亦称偏序集分解定理,该定理断言:
对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。
此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目。
通俗讲:划分原序列的LDS数目必定等同于原序列中的LIS长度
通过题目描述,用n^2的暴力方法会超时,所以用nlogn的优化方法
LIS、LDS的优化 O(NlogN):
设数组 d 表示 当前 的最长上升子序列, len 表示其长度。那么 d[len] 就表示当前最长上升子序列的最后一个元素。
一开始 len=1,dlen=a1,之后开始向后遍历,考虑当前遍历到的 ai :
若 ai≥dlen ,则直接放入 d 的末尾
若 ai<dlen ,则在 d 中找到第一个大于它的数,插入进去,并丢弃在他之后的元素
AC代码:
#include<bits/stdc++.h>
#define endl "\n";
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+7;
int a[maxn];
int LIS[maxn],LDS[maxn];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
/* freopen("D:\\Code\\C++\\in.txt","rt",stdin);
freopen("D:\\Code\\C++\\out.txt","wt",stdout); */
int num=1;
while(cin>>a[num])
{
num++;
}
num--;
int len1=1,len2=1;
LIS[1]=a[1];
LDS[1]=a[1];
for(int i=2;i<=num;i++)
{
if(a[i]<=LIS[len1])
LIS[++len1]=a[i];
else
*upper_bound(LIS+1,LIS+1+len1,a[i],greater<int>()) = a[i];
if(a[i]>LDS[len2])
LDS[++len2]=a[i];
else
*lower_bound(LDS+1,LDS+1+len2,a[i]) = a[i];
}
cout<<len1<<endl;
cout<<len2;
return 0;
}