3 solutions

  • 5
    @ 2024-7-15 23:37:39

    解析见代码

    /*先讲一下思路:
     本题来源于Noip1999(启蒙域A1260)
     原题可以用O(n^2)算法过,但本题需要用O(nlogn)
      原本的动态规划算法显然是不够的
      最多能拦截几枚导弹,本质上就是一个最长不上升序列的长度(反正只有一套)(不一定连续)
      需要配备几套系统,本质上就是一个最长上升序列的长度(高出去的要重新配备一套) 
      理论存在,实践开始! 
     */ 
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100010;
    int f[N];  //f数组存储的是最长不上升序列(注意不是子序列) 
    int g[N];  //g数组存储的是最长上升序列(注意不是子序列)
    int h[N];  //h数组存储导弹的高度  
    int n;//n纯粹一个过程量,循环输入用的,可以优化 
    int main() {
    	while (cin >> h[++ n]);//这里之所以使用++n而非n++,是因为n要从1开始(当然如果你初始化n=1,那么就用n++) 
    	n--; 
    	int res = 1, cnt = 1;//res和cnt的用法一致,只不过为区分用处,所以用了不同的名字 
    	f[1] = g[1] = h[1];//初始化 
    	for (int i = 2; i <= n; i ++ ) {//请注意,因为前面已经有一步n--的操作,所以这里的n实质上是n-1,由于已经初始化f,g,h数组的第一项一致,所以只需要从2开始 
    		if (h[i] <= f[res]) f[++ res] = h[i];//若出现不大于(即不上升子序列的下一项)则自动补入 
    		else{
    			int k = upper_bound(f + 1, f + res + 1, h[i], greater<int>()) - f;
    			/*如果导弹的高度已经超出范围,那么就在已求出范围用upper_bound函数寻找
    			第一个<高度的,选择拦截更高的导弹,从而给出更大限度的发挥空间*/ 
    			f[k] = h[i];//根据地址锁定  
    		}
    		if (h[i] > g[cnt]) g[++ cnt] = h[i];//g数组同理,只不过加不加greater看情况 
    		else{
    			int k = lower_bound(g + 1, g + cnt + 1, h[i]) - g;
    			g[k] = h[i];
    		}
    	}
    	printf("%d\n%d\n", res, cnt);//输出 
    	return 0;
    }
    //代码来自CSDN,注释是本人写的 
    
    
    
    
    /*附加样例分析:
    第一步,先统一第1项高度为h[1]=389
    第二步,满足207<=389(即f[1]),故f[2](即f[++1])=207,res=2;
    		不满足207>389,查找后得k=1,207替换389;
    第三步,满足155<=207,故f[3]=155,res=3;
    		不满足155>207,查找后得k=1,155替换207;
    第四步,不满足300>=155,查找后得k=2,300替换207;
    		满足300>155,cnt=2
    		……
    以此类推,
    得res=6,拦截的6枚分别为389,300,299,170,158,65
    cnt=2,需要配备初始射程为389,300的两套发射系统
    */
    

    Information

    ID
    20
    Time
    1000ms
    Memory
    128MiB
    Difficulty
    3
    Tags
    # Submissions
    174
    Accepted
    31
    Uploaded By