题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是\le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出格式
输入格式:
1行,若干个整数(个数\le 100000≤100000)
输出格式:
22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出样例
输入样例#1: 复制
389 207 155 300 299 170 158 65
输出样例#1: 复制
6 2
说明
为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分
每点两问,按问给分
下面是n*n复杂度的算法
主要思考就是我们每次在选不选第i个的时候,都去遍历之前的点,考虑以他们为最后一个点的情况,所以大小就是max(res[j]+1,1),但是我们max是记录最大值的,所以还要和自己取一个最大值,然后把n次中最大的值取成结果。
至于需要多少个系统,可以用Dilworth知道,他的系统的个数就是反链表的最大的长度。,所以就是最大上升序列的长度。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int a[100002] ;
int res[100002];
int main()
{
int count = 1;
while (cin >> a[count])
count++;
res[1] = 1;
int re = 0;
for (int i = 2; i < count; i++)
{
int MAX = 1;
res[i] = 1;
for (int j=1;j<i;j++)
{
if (a[i] <= a[j])
MAX = max(max(res[j] + 1, 1), MAX);
}
res[i] = MAX;
re = max(res[i], re);
}
cout << re << endl;
re = 0;
for (int i = 2; i < count; i++)
{
int MAX = 0;
res[i] = 1;
for (int j = 1; j < i; j++)
{
if (a[i] > a[j]) MAX = max(max(res[j] + 1, 1), MAX);
}
res[i] = max(MAX,res[i]);
re = max(re, res[i]);
}
cout << re<< endl;
return 0;
}
如果采用二分的做法
我们开一个f数组来表示长度为I的上升子链的最小值,用1个ans来记录当前最长链的长度,
如果a[i]<=f[ans], 则 ans++, f[ans]=a[i];
否则就二分查找恰好以a[i]为结尾的子链的位置,并判断是否更新它。
f[i]存储长度为i时该单调序列的结束点。通过下面的举例分析说明。记ans为当前最大标记。
做法类似这个图。
还有一个需要注意的就是二分的写法。二分最好写成左闭右开的情况。
最好取中点的时候写成a+(b-a)/2;防止溢出
写法这种比较好
while (x <y)
{
int mid = x + (y - x) / 2;
if (res[mid] >= a[v]) x = mid + 1; //注意看二分的变化
else y = mid;
}
#include<iostream>
#include<vector>
#include<climits>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
int a[100002] ;
int res[100002];
int BiSe(int x, int y, int v)
{
while (x <= y)
{
int mid = x + (y - x) / 2;
if (res[mid] >= a[v]) x = mid + 1; //注意看二分的变化
else y = mid - 1;
}
return x;
}
int BiSe1(int x, int y, int v) //二分求上界
{
while (x <= y)
{
int mid = x + (y - x) / 2;
if (res[mid] <a[v]) x = mid + 1;
else y = mid - 1;
}
return x;
}
int main()
{
int count = 1;
while (cin >> a[count])
count++;
res[0] = 1000000;
int p = 0;
for (int i = 1; i < count; i++)
{
if (res[p] >= a[i])
{
p++;
res[p] = a[i];
}
else
{
int l=BiSe(1, p,i);
if(l>0)
res[l] = a[i];
}
}
cout << p << endl;
res[0] = -1000000;
p = 0;
for (int i = 1; i < count; i++)
{
if (res[p] < a[i])
{
p++;
res[p] = a[i];
}
else
{
int l = BiSe1(1, p, i);
res[l] = a[i];
}
}
cout << p;
return 0;
}