1012 [NOIP1999]拦截导弹 最长单调不增子序列 伪数据
链接:https://ac.nowcoder.com/acm/problem/16810
来源:牛客网
题目描述
输入描述:
1行,若干个整数(个数≤100000)
输出描述:
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
分析
这道题是个伪1w,总共十个炸弹都没有,所以最长单调递增子序列就可以做了。。
此题有两个问题,第一求这套系统最多能拦截多少导弹,第二个求如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
第一个问题即为求最长下降子序列,不多阐述。
对于第二个问题我是用贪心求解的。
对于每一个处在i位置的导弹,它可以和(从1到i-1位置且还没有被击落的)任一大于等于其高度的导弹共在一套装置(意思即为无需添置新的装置),在此想既然是选一个符合要求的导弹共处一套装置,则选对于之后的更有利的导弹(即为选比位置i导弹高度高的所有导弹中高度最小的那个,可以好好思考一下为何如此选)。(易错点)
#include<bits/stdc++.h>
#define dbb(i,a,b) cout<<#i<<':'<<i<<' '<<#a<<':'<<a<<' '<<#b<<':'<<b<<endl;
using namespace std;
const int N = 1e5+10;
int n;
int f[N],flag[N],a[N],cnt,g[N],res;
void solve() {
memset(f,0,sizeof f);
for(int i = 1;i<=n;i++) {
f[i] = 1;
for(int j = 1;j<i;j++) {
if(a[j] >= a[i] && !flag[j] && !flag[i]) {
if(f[i] < f[j] + 1) {
f[i] = f[j] + 1;
g[i] = j;
}
}
}
}
// for(int i = 1;i<=n;i++) cout<<f[i]<<' ';
// cout<<endl;
int t,ans = 1;
for(int i = 1;i<=n;i++) {
if(f[i] > ans && !flag[i]) {
ans = f[i];
t = i;
}
}
if(!cnt) cout << ans<<endl;
cnt += ans;
res ++ ;
for(int i = 0;i<ans;i++) {
flag[t] = 1;
t = g[t];
}
}
int main() {
n = 1;
while(cin>>a[n])n ++;
n -- ;
while(cnt != n) {
solve();
}
cout<<res<<endl;
}