題目描述
某國爲了防禦敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。
輸入導彈依次飛來的高度(雷達給出的高度數據是≤50000的正整數),計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。
輸入輸出格式
輸入格式:
1行,若干個整數(個數≤100000)
輸出格式:
2行,每行一個整數,第一個數字表示這套系統最多能攔截多少導彈,第二個數字表示如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。
輸入輸出樣例
輸入樣例#1: 複製
389 207 155 300 299 170 158 65
輸出樣例#1: 複製
6 2
說明
爲了讓大家更好地測試n方算法,本題開啓spj,n方100分,nlogn200分
每點兩問,按問給分
解題思路:
第一問還是很好想到的,最長下降子序列。用二分即可求出,不會做的去LeetCode看看吧,暫時我還沒寫,所以沒鏈接。
主要是第二問,多少套系統?
其實思路 和第一問類似,,不過是求最長上升子序列。
試想一下,每套系統都肯定有一個攔截的最低導彈,那麼,我的第一套系統攔截了一顆較低的導彈,假如下一顆導彈要高於這顆,那麼就需要新的攔截系統了。
舉個例子:【10,9,5,6,8,2,1】
我的第一套系統 equ[0] 先攔截10,在攔截9(這時equ[0]更新爲9),再攔截5(equ[0]==5);
到 6 的時候,equ[0]==5 < 6,所以需要一個新的系統去攔截也就是equ[1]==6;
這樣一看,實際上就是再求最長上升子序列問題。
如此一來就好做了。
反思錯誤:
①沒看清題,以後的每發“不高於”前一發。。可以等於的。
②因爲習慣用快讀,結果快讀不會無限制的輸入。錯了一波,尷尬,現在的快讀無限制輸入也是瞎寫的。
java代碼(代碼量看着多,實際上很少,在SO的solution纔是代碼):O(nlogn)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
// long sta = System.nanoTime();
InputStream is = System.in;
OutputStream os = System.out;
IN cin = new IN(is);
PrintWriter cout = new PrintWriter(os);
SO so = new SO();
so.solution(cin, cout);
// long end = System.nanoTime();
// cout.println("耗時:" + (double)(end-sta)/1e6 + "ms");
cout.close();
}
static final int MOD = (int)1e9 + 7;
static class SO {
int max = 100000;
int[] cat = new int[max+1];
int top1 = 0;
int[] equ = new int[max+1];
int top2 = 0;
void one(int cur) {
int l = 0, r = top1-1;
while(l<r) {
int m = l + (r-l)/2;
if(cat[m]>=cur)l=m+1;
else r=m;
}
cat[r] = cur;
}
void two(int cur) {
int l = 0, r = top2-1;
while(l<r) {
int m = l + (r-l)/2;
if(equ[m]<cur)l=m+1;
else r=m;
}
equ[r] = cur;
}
void solution(IN cin, PrintWriter cout) {
String s;
int cur;
while((s=cin.next())!=null) {
cur = Integer.parseInt(s);
if(top1==0 || cat[top1-1]>=cur)cat[top1++]=cur;
else one(cur);
if(top2==0 || equ[top2-1]<cur)equ[top2++]=cur;
else two(cur);
}
cout.println(top1+"\n"+top2);
}//end solution
}//end SO
//以下是快讀部分
static class IN {
private BufferedReader reader;
private StringTokenizer tokenizer;
private String s;
IN(InputStream is) {
reader = new BufferedReader(new InputStreamReader(is), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
s = reader.readLine();
if(s==null)return null;
tokenizer = new StringTokenizer(s);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
}