CCF/202012-2期末预测之最佳阈值 前缀和

考的时候完全没想到这个方法,算法知识储备过于贫瘠。记录一下。
题目链接

思路

m最大到100000,暴力法n次遍历就超时了

因此需要先根据y值(安全指数)从小到大排序,再用类似前缀和的方法计算出每一个输入,它之前(安全系数y比他小)result为0的数的个数,以及它之后(安全系数y比它大)result为0的数的个数,两者之和就是我们想比较的sum。这种方法算sum只需遍历2遍,正着一遍求0,逆着一遍求1。

最后找到最大的sum值对应的最大安全指数y就是输出结果。

前缀和

最简单的一个例子就是给定 n 个数和 m 次询问,每次询问一段区间的和。求一个 O(n + m) 的做法。
如果这n个数就是1~100,
那么sum数组里依次存放的就是1,(1+2),(1+2+3),…,(1+2+…+100),创建sum数组的过程一次遍历即可完成。
然后如果想知道任何一段区间的和,比如3~48的和,只需sum[48]-sum[2]

//核心代码
for(int i = 1; i <= n; ++i)
	sum[i] = sum[i - 1] + a[i];  //O(n)
while(m--)        //O(m)
{
	int L, R; 
	scanf("%d%d", &L, &R);
	printf("%d\n", sum[R] - sum[L - 1]);
}

题目代码

#include <iostream>
#include <algorithm>
using namespace std;
struct Mypair{
	int y;
	int result;
	int before;
	int after;
	int sum;
};
Mypair array[100000];

int cmp(Mypair pair1, Mypair pair2){
	return pair1.y < pair2.y; 
}
int cmp2(Mypair pair1, Mypair pair2){
	if(pair1.sum == pair2.sum)
		return(pair1.y>pair2.y); 
	else{
		return pair1.sum>pair2.sum;
	}
}
int main(){
	int m;
	scanf("%d",&m);
	for(int i = 0;i<m; ++i){
		scanf("%d %d",&array[i].y,&array[i].result);
	} 
	sort(array,array+m,cmp);
	
	//求before,正着遍历一遍  
	array[0].before = 0;
	int preY = array[0].y;
	int preIndex = 0;
	
	for(int i = 1;i<m;++i){
		if(array[i].y == preY){
			//对于类似(3 0)(3 1)(3 0)的数据的处理
			array[i].before = array[i-1].before;
		}else{
			int tsum = 0;
			for(int j = preIndex;j<i;j++){
				tsum += array[j].result == 0 ? 1:0;
			}
			array[i].before = array[i-1].before + tsum;
			preY = array[i].y;
			preIndex = i;
		}	
	}
	
	//求after,逆着遍历一遍 
	array[m-1].after = array[m-1].result == 1?1:0;
	array[m-1].sum = array[m-1].before + array[m-1].after;
	preY = array[m-1].y;
	preIndex = m-1;
	
	for(int i = m-2;i>=0;i--){
		if(array[i].y == preY){
			array[i].after = array[i+1].after;
		}else{
			int tsum = 0;
			for(int j = preIndex;j>i;j--){
				tsum += array[j].result == 1?1:0;
			}
			array[i].after = array[i+1].after + tsum;
			preY = array[i].y;
			preIndex = i;
		}
		array[i].sum =  array[i].before + array[i].after;
	}
//	for(int i = 0;i<m;i++){
//		printf("y: %d before:%d after:%d\n",array[i].y,array[i].before,array[i].after);
//	}
	sort(array,array+m,cmp2); //根据sum和y排序 
	printf("%d",array[0].y);	
	return 0;
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值