Subtask #0
第一问思路:
因为发射高度一次不如一次可得知,就是求单调不上升子序列(即后一项总是不大于前一项)
可以记 d p [ i ] dp[i] dp[i] 表示「对于前 i i i 个数,在选择第 i i i 个数的情况下,得到的单调不升子序列的长度最长是多少」。于是可以分两种情况:
- 第 i i i 个数是子序列的第一项。则 d p [ i ] dp[i] dp[i]为1
- 第 i i i 个数不是子序列的第一项。选择的第 i i i 个数之前选择了第 j j j 个数。根据题意,第 j j j 个数应当小于第 i i i 个数的值 。枚举这样的 j j j ,可以得到状态转移方程:
dp[i]=max(dp[i],dp[j]+1)
- 考虑到求最大拦截导弹的数,所以在 d p dp dp 数组中寻找最大值:
ans=max(ans,dp[i]);
//1≤i≤n
所以,第一问代码长这样:
for(int i=1;i<=n;i++)
{
for(int j=i;j>0;j--)if(a[i]<=a[j])dp[i]=max(dp[i],dp[j]+1);
ans=max(ans,dp[i]);
}
cout<<ans-1<<endl;
时间复杂度为 O ( n 2 ) \mathcal O(n^2) O(n2)
第二问思路:
其实就是求输入进来的数组的最长不上升子序列
这里的 d p [ i ] dp[i] dp[i] 也可分为两种情况
- 第 i i i 个数是子序列的第一项。则 d p [ i ] dp[i] dp[i]为1
- 第 i i i 个数不是子序列的第一项。选择的第 i i i 个数之前选择了第 j 个数。根据题意,第 j j j 个数应当大于第 i i i 个数的值 。枚举这样的 j j j,可以得到状态转移方程:
dp[i]=max(dp[i],dp[j]+1);
所以,第二问代码长这样:
for(int i=1;i<=n;i++)dp[i]=1;
for(int i=2;i<n;i++)
{
for(int j=i-1;j>=1;j--)
{
if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans;
时间复杂度也为 O ( n 2 ) \mathcal O(n^2) O(n2)
参考代码:
#include<bits/stdc++.h>
using namespace std;
int n=1,ans=0,dp[100000],a[100000];
int main()
{
while(cin>>a[n])n++;
for(int i=1;i<=n;i++)
{
for(int j=i;j>0;j--)if(a[i]<=a[j])dp[i]=max(dp[i],dp[j]+1);
ans=max(ans,dp[i]);
}
cout<<ans-1<<endl;
ans=0;
for(int i=1;i<=n;i++)dp[i]=1;
for(int i=2;i<n;i++)
{
for(int j=i-1;j>=1;j--)
{
if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans;
return 0;
}
Subtask #1
洛谷上的数据被加强了,要拿到200分的话,就要用 O ( n log n ) \mathcal O(n\log n) O(nlogn) 做法通过。
第一问思路:
因为时间复杂度要在 O ( n log n ) \mathcal O(n\log n) O(nlogn) 内,所以考虑二分
第二问思路:
可以考虑贪心
从左到右依次枚举每个导弹。假设现在有若干个导弹拦截系统可以拦截它,那么我们肯定选择这些系统当中位置最低的那一个。如果不存在任何一个导弹拦截系统可以拦截它,那我们只能新加一个系统了。
参考代码
#include <bits/stdc++.h>
using namespace std;
int n=1,f[1000000],a[1000000],t;
int main()
{
while(cin>>a[n])n++;
t=0,memset(f,0,sizeof(f)),f[0]=2147483647;
for(int i=1;i<n;i++)
{
int l=0,r=t+1,m;
while(r-l>1)
{
if(f[m=l+(r-l)/2]>=a[i])l=m;
else r=m;
}
int x=l+1;
if(x>t)t=x;
f[x]=a[i];
}
cout<<t<<endl;
t=0;
memset(f,0,sizeof(f)),f[0]=0;
for(int i=1;i<n;i++)
{
int l=0,r=t+1,m;
while(r-l>1)
{
if(f[m=l+(r-l)/2]<a[i])l=m;
else r=m;
}
int x=l+1;
if(x>t)t=x;
f[x]=a[i];
}
cout<<t;
return 0;
}