相信对于最大上升子序列大家已经不再陌生(不知道的下面我也会介绍),动态规划的方法确实非常好理解,但时间复杂度太高,下面我将会用更短时间复杂度的单调数组来做出这道题。
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入
第1行:依次输入若干个导弹的高度H(1≤H≤30000),导弹的个数N≤5000
输出
第1行:一个整数,表示单枚炮弹能拦截多少导弹 第2行:一个整数,表示拦截所有导弹最少要配备多少套这种导弹拦截系统
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
389 207 155 300 299 170 158 65
样例输出
6 2
我先来解释一下题面,如果一个系统拦截了一定高度的导弹,那么他就只能在拦截比他更矮高度的导弹,并且这次拦截之后只能拦截比这次更矮的导弹。拿样例举例子:如果一个系统拦截了第一个导弹"389",那么他就只能拦截比389更矮的导弹,假如我们拦截了207,则之后就只能拦截比207更矮的导弹
本题要我们求需要几套系统,及一个系统最多能拦截多少导弹。我们想:如果在这些导弹中,有一个子序列是下降并且是这些导弹中数量最长的,那么他就能拦截最多的导弹,不知道我说清楚没有,因为单套系统能拦截的导弹是下降的,所以一个系统最多能拦截多少导弹求的就是最长下降子序列。
我们再来考虑需要几套系统。假设我们得到了最小划分的K组导弹,从第a(1<=a<=K)组导弹中任取一个导弹,必定可以从a+1组中找到一个导弹的高度比这个导弹高(因为假如找不到,那么它就是比a+1组中任意一个导更高,在打第a组时应该会把a+1组所有导弹一起打下而不是另归为第a+1组),同样从a+1组到a+2组也是如此。那么就可以从前往后在每一组导弹中找一个更高的连起来,连成一条上升子序列,其长度即为K;
动态规划很简单,我就直接上代码了
看不懂的可以看看我的这篇博客
//DP,设dp[i]为从1到i的最长下降子序列,dp2[i]为上升
#include
using namespace std;
int n,dp[30001],dp1[30001],a[5001],maxa=-1,maxb=-1;
int main() {
int i=1;
for(int i=1;i<=30001;i++)//初始化,每个导弹都可以算作一个
dp[i]=dp1[i]=1;
while(cin>>a[i])
i++;
n=i-1;
for(int i=1;i<=n;i++)//求最优的状态
for(int j=1;ja[j])
dp[i]=max(dp[i],dp[j]+1);
for(int i=1;i<=n;i++)
for(int j=1;j
这道题并不能用单调队列,具体原因这里不再赘述,可以看看我的这篇博客。
我这里用的是另一种方法,维护单调数组来达到求最大上升和下降子序列,并结合了2分的思想。为了更好的讲解,我先把求最长上升子序列的代码亮出来,下降来由同志么自行补充(不是我懒,而是想让你们不要只抄代码,还要理解思路)
#include
#include
using namespace std;
#define N 100010
#define LL long long
#define inf 0x7f7f7f7f7f7f
int read() {
int f=1,s=0;char a=getchar();
while(!(a>='0'&&a<='9')) {if(a=='-') f=-1 ; a=getchar(); }
while(a>='0'&&a<='9') {s=s*10+a-'0'; a=getchar();}
return f*s;
}
LL n,a[N],t,k=0,sum,a1[N],k1;
int main()
{
a[0]=1ll<<60;
while(cin>>sum) {
if(sum<=a[k]) {//维护单调性,k为下降序列的最大长度
a[++k]=sum;
continue;
}
int l=0,r=k,mid;
while(la[mid]) r=mid-1;
else l=mid;
}
a[l+1]=sum;
}
cout<
如果你连单调是什么都不知道,请看:还是这篇博客
代码中,我们的目的就是维护序列的单调性,a数组便是这个最长下降子序列。
这里写得比较潦草,但如果你看了我的前两篇博客,也会很好的理解。
LGOJ导弹拦截
让我们来对比一下时间复杂度(不要问我中间的错误是怎么回事)