100pts变70pts求助!
查看原帖
100pts变70pts求助!
671223
OAIM楼主2024/3/24 14:48

题目要求时间复杂度达到O(nlogn)才能过关,把100pts的代码优化了一下,但是优化后变成70pts了,其余的点都是TLE。


优化后的整体思路是: 先求第一问,将导弹高度和dp值存入pair数组中,按照导弹高度快速排序,然后二分找到高于当前查找的导弹的最小高度,再对这个找到的位置及之后的所有导弹按照dp值排序,取最后一个+1就是当前导弹的dp最大值。 然后求第二问,用dp存每个系统的最小导弹高度,利用二分找到高于当前导弹高度的最小系统高度,求出当前导弹所在的系统(无法在前面系统则新开一个系统),然后对所有系统的最小高度值进行快速排序。


总觉得这个思路的时间复杂度就是O(nlogn),但实际运行的时间还不如没优化前的O(n^2),请教各位大佬,帮忙改改代码。


//导弹拦截

//导弹的最高高度非递增
//求最多能拦截多少导弹和最少要配备多少套导弹拦截系统 
//不能用单调栈
//找最长的非递增子序列 
//每套系统用能打到的最小高度标记 

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 1e5 + 10;

typedef pair<int,int> PII;

int h[N];//导弹的高度 
int n;//导弹个数
int dp[N];//dp[i]:以i号导弹结尾的最长非递增子序列 
int cnt = 0;//多少套 
int m = 0;//最多能拦截多少导弹 
int sum = 0;//已经拦截的导弹数

//快速排序1
void quick_sort1(vector<PII> &res,int l,int r){
	if(l >= r){
		return;
	}
	
	PII x = res[l];
	int i = l - 1,j = r + 1;
	while(i < j){
		do{
			i++;
		}while(res[i].first < x.first);
		do{
			j--;
		}while(res[j].first > x.first);
		if(i < j){
			swap(res[i],res[j]);
		}
	}
	
	quick_sort1(res,l,j);
	quick_sort1(res,j + 1,r);
} 

//快速排序
void quick_sort2(vector<PII> &res,int l,int r){
	if(l >= r){
		return;
	}
	
	PII x = res[l];
	int i = l - 1,j = r + 1;
	while(i < j){
		do{
			i++;
		}while(res[i].second < x.second);
		do{
			j--;
		}while(res[j].second > x.second);
		if(i < j){
			swap(res[i],res[j]);
		}
	}
	
	quick_sort2(res,l,j);
	quick_sort2(res,j + 1,r);
}

//快速排序
void quick_sort3(int l,int r){
	if(l >= r){
		return;
	}
	
	int x = dp[l];
	int i = l - 1,j = r + 1;
	while(i < j){
		do{
			i++;
		}while(dp[i] < x);
		do{
			j--;
		}while(dp[j] > x);
		if(i < j){
			swap(dp[i],dp[j]);
		}
	}
	
	quick_sort3(l,j);
	quick_sort3(j + 1,r);
} 

//二分查找
int bsearch1(vector<PII> res,int x){
	int l = 0,r = res.size() - 1;
	int mid = (l + r) >> 1;
	int a,b;
	
	while(l < r){
		mid = (l + r) >> 1;
		a = res[mid].first;
		b = res[mid].second;
		
		if(a >= x){
			r = mid;
		}else{
			l = mid + 1;
		}
	}
	
	if(res[l].first < x){
		//没有符合条件的 
		return -1;
	}
	
	//快速排序
	quick_sort2(res,l,res.size() - 1);
	
	return res[res.size() - 1].second;
} 

//二分查找
int bsearch2(int x){
	int l = 1,r = cnt;
	int mid = (l + r) >> 1;
	
	while(l < r){
		mid = (l + r) >> 1;
		if(dp[mid] >= x){
			r = mid;
		}else{
			l = mid + 1;
		}
	}
	
	if(dp[l] < x){
		//没有符合条件的 
		return -1;
	}
	
	return l; 
} 

//第一问的动态规划 
int f1(){
	int ans = 1;
	vector<PII> res;//按顺序存所有dp结果
	dp[1] = 1;
	res.push_back({h[1],dp[1]});
  
	//枚举所有导弹
	for(int i = 2;i <= n;i++){
		//找前面所有的可拦截导弹个数最多的
		dp[i] = 1;
		int a;
		int b;
		//二分查找第一个大于等于自己高度的
		int t = bsearch1(res,h[i]);
		if(t != -1){
			//有符合条件的
			dp[i] = t + 1; 
		}
		res.push_back({h[i],dp[i]});
		if(ans < dp[i]){
			ans = dp[i];
		}
		//重新排序
		quick_sort1(res,0,res.size() - 1);
	} 
	
	return ans;
}
//第二问
void f2(){
	//枚举所有导弹 
	for(int i = 1;i <= n;i++){
		//找前面的系统中最低导弹高度最小的大于等于当前导弹高度的
		//从小到大枚举所有导弹系统 
		bool flag = false;//是否找到了可以打到的系统 
		
		//二分查找上一个大于自己的最小值 
		int t = bsearch2(h[i]);
		if(t != -1){
			//有符合条件的 
			flag = true;
			dp[t] = h[i]; 
			//printf("dp[%d]=%d\n",t,dp[t]);
		}
		
		if(!flag){
			//没有系统可以打到
			//新开一个系统
			cnt++;
			dp[cnt] = h[i]; 
		}

		quick_sort3(1,cnt);
	}
} 

int main(){
	//输入
	/*do{
		n++;
		scanf("%d",&h[n]);
	}while(getchar() != '\n');*/
	while(scanf("%d",&h[n + 1]) != EOF){
		n++;
	}

	//判断一套系统最多能拦截多少导弹 
	m = f1();
	
	//判断需要多少套
	memset(dp,0,sizeof(dp));
	f2();
	
	//输出
	printf("%d\n%d",m,cnt); 
	
	return 0;
}
2024/3/24 14:48
加载中...