导弹拦截题目出处(3757)
本学校机房dalao出去学习后把最长上升子序列改了一下,然后因为数据大就炸了,就去学了一下nlogn算法。。。。。。
这个其实本质还是DP,但是在里面加了贪心的因素,大概就是用另一个数组来存这个最长上升子序列,但是在里面有一些改动。
我们来想哈,既然我们要求TA的最长上升子序列,我们在这里分两种情况:
(len代表已经搜到的最长上升子序列的长度)
1、a[i]>dp[len],直接把a[i]放在dp[len]的后面
2、a[i]<=dp[len],那我们就在离TA的值最近的那个数,然后把dp[k](权当把这个位置记作k)替换成a[i]
为什么呢
既然我们要求TA的最大长度嘛,我们就要把比TA大的最小的那个数尽可能的改小,因为要使后面的这些尽量都能安在这个最长上升子序列后面。
大家能明白吗???
先上代码:
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
inline void pr(int x) {
if(x>9)pr(x/10);
putchar(x%10);
}//快输不解释
int a[100005],dp1[100005],dp[100005],i,k1=1,k=1/*k和k1代指长度*/,n=1;
struct cmp {//这个cmp其实就是在二分查找中用得到
bool operator()(int a,int b) {
return a>b;
}
};
int main()
{
while(~scanf("%d",&a[n]))
n++;
n--;
dp[1]=dp1[1]=a[1];
for(i=2;i<=n;i++) {
if(dp[k]>=a[i])//根据题意来,求最多可以打多少颗导弹
dp[++k]=a[i];
else
dp[upper_bound(dp+1,dp+k+1,a[i],cmp())-dp]=a[i];//就二分查找搜最大的那个呗
if(dp1[k1]<a[i])//这个就是反着来,求最少需要多少套系统
dp1[++k1]=a[i];
else
dp1[lower_bound(dp1+1,dp1+k1+1,a[i])-dp1]=a[i];//反着搜,缩时间复杂度
}
pr(k),putchar('\n'),pr(k1);
}
对lower_bound和upper_bound不熟的请戳
我好像把自己绕进去了。。。。。。
看不懂的可以戳,这篇里面解释的非常详细。