P1020 [NOIP1999 普及组] 导弹拦截
题目链接:https://www.luogu.com.cn/problem/P1020
思路:题目要求输出两个数,分别是用一个系统最多可以拦截多少个,用几个系统可以全部拦截。
由于系统每发炮弹发射的高度不能高于上次发射炮弹的高度,所以我们找到从某个炮弹开始,他后面的炮弹的高度不高于他的个数。找到这个数的最大值就是用一个系统可以拦截的最大个数。那么也就是求到某个数的最长不上升子序列。
第二问求用几个系统可以全部拦截,由于系统没发炮弹发射的高度不能高于上次炮弹发射的高度,所以,如果当前炮弹的高度比上一个炮弹的高度高那么就不能拦截,假设当前大炮为i,那么i的范围就是1-n,n是导弹的个数。
所以我们要求出到第i个数的最长上升子序列
求最长不上升子序列 设dp[i]为到第i个数的最长不上升子序列,如果arr[j]>=arr[i] 那么dp[i]=dp[j]+1; j的范围是1-i-1
求最长上升子序列 设dp[i]为到第i个数的最长上升子序列,如果arr[j]<arr[i],那么dp[i]=dp[j]+1; j的范围是1-i-1
下面这个代码提交只能过的100分,因为这是用O(N²)的方法求的
#include<bits/stdc++.h> using namespace std; const int maxn=100010; int arr[maxn],n; int dp1[maxn],dp2[maxn]; void INPUT(){ while(cin>>arr[++n]); n--; } void solve(){ int a=0; for(int i=1;i<=n;i++){ dp1[i]=1; //cout<<"i:"<<i<<" "<<arr[i]<<endl; for(int j=i-1;j>=1;j--){ if(arr[j]>=arr[i]){ //cout<<j<<" "<<arr[j]<<endl; dp1[i]=max(dp1[i],dp1[j]+1); } } a=max(a,dp1[i]); } cout<<a<<endl; int b=0; for(int i=1;i<=n;i++){ dp2[i]=1; for(int j=i-1;j>=1;j--){ if(arr[j]<arr[i]){ dp2[i]=max(dp2[i],dp2[j]+1); } } b=max(b,dp2[i]); } cout<<b<<endl; } int main(){ INPUT(); //calc(); solve(); return 0; }
200分代码O(nlogn)
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; int arr[maxn],n; int dp1[maxn],dp2[maxn]; void INPUT(){ while(cin>>arr[++n]); n--; } void solve(){ //sort(arr+1,arr+1+n); int len1=1; int a=0; dp1[len1]=arr[1]; for(int i=2;i<=n;i++){ //cout<<dp1[len1]<<" "; if(arr[i]<=dp1[len1]){ dp1[++len1]=arr[i]; }else{ int p=upper_bound(dp1+1,dp1+1+len1,arr[i],greater<int>())-dp1; dp1[p]=arr[i]; } } cout<<len1<<endl; int len2=1; dp2[len2]=arr[1]; for(int i=2;i<=n;i++){ if(arr[i]>dp2[len2]){ dp2[++len2]=arr[i]; }else{ int p=lower_bound(dp2+1,dp2+1+len2,arr[i])-dp2; dp2[p]=arr[i]; } } cout<<len2<<endl; } int main(){ INPUT(); //calc(); solve(); return 0; }
浙公网安备 33010602011771号