洛谷P1020 導彈攔截
阿新 • • 發佈:2018-12-12
題目連結
思路1:
動態規劃,利用表示到第個導彈時所攔截的總導彈數,則有 對於第二問,“攔截所有導彈最少要配備多少套這種導彈攔截系統”,利用序列的不下降子序列最少劃分數等於上升序列的總長度這一原理,即是求最長上升子序列的長度。 時間複雜度,過一半資料。
#include<iostream>
#include<cstdio>
using namespace std;
int f[100010 ],f2[100010];
int a[100010],b[100010];
//f[i]=max(f[i],f[j]+1) i>j&&a[i]<=a[j]
int main(int argc, char** argv) {
int m=1,ans=-1,cnt=1;
while(scanf("%d",&a[m])!=EOF){
f[m]=1,f2[m]=1;++m;
continue;
}
--m;
for(int i=1;i<=m;i++){
for(int j=1;j<i;j++){
if(a[i]<=a[j]) f[i] =max(f[i],f[j]+1);
}
if(ans<f[i]) ans=f[i];
}
for(int i=1;i<=m;i++){
for(int j=1;j<i;j++){
if(a[i]>a[j]) f2[i]=max(f2[i],f2[j]+1);
}
cnt=max(cnt,f2[i]);
}
printf("%d\n%d\n",ans,cnt);
return 0;
}
思路2:
利用維護最長非增序列的每個時刻的最大值,這時的已經不再是思路1中的用來表示到第個導彈時攔截的導彈總數,而是表示攔截到的第個導彈的最大值。舉個栗子,如這組資料90 103 99 83 102 70 86 70 99 71,由於我們求的是最長非增子序列,初始化,當遇到時,即更新的值為;反之,如果,則增加攔截的新導彈數。以此類推,最終更新得到的為103,102,99 ,71,70,表示可能攔截到的第個導彈的最大值為。 注意到始終為單調非增序列,故可以利用二分查詢提高效率。 時間複雜度,通過全部資料。
#include <iostream>
#include<cstdio>
using namespace std;
int f[100010],f2[100010];
int a[100010],b[100010];
//利用f[i]維護最長非增序列的每個時刻的最大值
int main(int argc, char** argv) {
int m=1;
while(scanf("%d",&a[m])!=EOF){
++m;
continue;
}
--m;
f[1]=a[1];
int ans=1,cnt=1;
for(int i=2;i<=m;i++){
if(a[i]<=f[ans]) f[++ans]=a[i];
else{
int l=1,r=ans;
while(l<r){
int mid=(l+r)>>1;
if(f[mid]>=a[i]) l=mid+1;
else r=mid;
}
f[l]=a[i];
}
}
f2[1]=a[1];
for(int i=2;i<=m;i++){
if(a[i]>f2[cnt]) f2[++cnt]=a[i];
else{
int l=1,r=cnt;
while(l<r){
int mid=(l+r)>>1;
if(f2[mid]<a[i]) l=mid+1;
else r=mid;
}
f2[l]=a[i];
}
}
printf("%d\n%d\n",ans,cnt);
return 0;
}