【uva10057】巧妙做法

这个题之前做过,方法太笨还不对,今天再做突然想到一个巧妙做法,网上应该也有别人用此方法的,因为并不是很难,但我没有看别人的,是自己想出来的哈哈哈

首先要对输入的数组进行排序,这是毋庸置疑的。

因为要计算绝对值的和,所以就想到了数轴上的距离的概念。要使|X1-A|+|X2-A|最小,也就是要找一个点A,使其到X1,X2距离和最短,所以很容易想到在数轴上只要A在X1和X2之间就行。

对排序后的数组进行操作,将首尾(最小值和最大值)抽取出来,A只要介于他俩之间就行,同理再将第二位和倒数第二位抽取出来,A要介于他俩之间才行......如此剥离下去,最后只会剩余一项或是两项。

所以提前判断数组的奇偶性,奇数的话A就是中间那项(很容易吧)偶数的话就是介于两数之间的所有数A都可以取,也就是有多个A值,但是最小的A值肯定还是左边的,因为右边的只会大于等于左边的。

计算有多少个A存在于数组中的时候,用到了algorithm算法自带的上下界函数(upper_bound()和lower_bound()),很好用的。

上ac代码,也是一次就过了哈哈哈

#include <iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int num,minA,numA,arr[1000005];

int main(){
	while(cin>>num){
		for (int i=0;i<num;i++){
			cin>>arr[i];
		}
		sort(arr,arr+num);
		//check the parity
		if (num%2==1){		//odd
			minA = arr[(num-1)/2];
			numA = upper_bound(arr,arr+num,minA)-lower_bound(arr,arr+num,minA);
			cout<<minA<<" "<<numA<<" "<<"1"<<endl;
		}
		else{				//even
			int a1=arr[num/2-1];
			int a2=arr[num/2];
			minA=a1;
			if (a1==a2){
				numA=upper_bound(arr,arr+num,minA)-lower_bound(arr,arr+num,minA);
				cout<<minA<<" "<<numA<<" "<<"1"<<endl;
			}
			else{
				numA=upper_bound(arr,arr+num,a2)-lower_bound(arr,arr+num,a1);
				cout<<minA<<" "<<numA<<" "<<a2-a1+1<<endl;
			}

		}
	}
	return 0;
}

【uva10057】巧妙做法

时间: 2024-08-07 21:05:07

【uva10057】巧妙做法的相关文章

C语言优化实例:一种消除嵌套switch-case的巧妙做法

我们有可能会写出或者遇到类似这样的代码: C/C++ switch (expr1) { case label11: switch (expr2) { case label21: // do something break; case label22: // do something break; default: // do something break; } break; case label12: switch (expr2) { case label21: // do something

C# 字符串详细使用

转自 http://www.cnblogs.com/candywyq/archive/2007/07/24/830021.html 1.Convert.ToInt32与Int32.Parse的恩恩怨怨 2.Split的3种用法 3.@"abc"和"abc"区别在那里 4.保留2位有效小数及四舍五入 5.url传递中文的解决方案 6.把123456789转换为12-345-6789的3种方法 7.交换两个指定位置字符的4种方法 8.“%10”的妙用 9.输出21个AA

Leetcode 175场周赛

2020-02-09 22:44:14 5332. 检查整数及其两倍数是否存在 给你一个整数数组 arr,请你检查是否存在两个整数 N 和 M,满足 N 是 M 的两倍(即,N = 2 * M). 更正式地,检查是否存在两个下标 i 和 j 满足: i != j0 <= i, j < arr.lengtharr[i] == 2 * arr[j] 我的方法:用了两个map,两个vector,还用了排序,有些麻烦: 我的想法是从前到后遍历的话,后面一定要是前面的两倍,否则无法判断: class S

kb-01-e&lt;取余操作,宽搜,巧妙&gt;;

题目描述: n属于1到200,找到对应的一个数只含有0和1,并且是n的倍数: 分析: 本题有几个数会是大数:所以要考虑大数: 用到余数的性质:例如n=6,1%6=1: 1*10%6=4:              (1*10+1)%6=5: 4*10%6=4:               (4*10+1)%6=5: 5*10%6=2:                (5*10+1)%6=3: (重复4,5) 2*10%6=2:                  ....=3: 3*10%6=0:

防止变量超过上限的巧妙办法

int n=0; int max = 100; //通常的做法(省略上下文) if(n>=max) {     n = 0; } n++; //巧妙的做法 n%=max n++ 防止变量超过上限的巧妙办法

hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙

/** 题目:hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4106 题意:给你n个数,每连续m个数,最多选k个数,问可以选的数的权值和最大多少. 思路:可以转化为区间k覆盖问题.区间k覆盖问题是每个点最多被k个区间覆盖.本题是每个区间最多选k个点. 刚好相反.我的做法有点不同其他博客那种做法.当然本质一样. 我这里的i就是原来n个数的下标,现在作为图中该数的节点编号

BZOJ 1079: [SCOI2008]着色方案(巧妙的dp)

BZOJ 1079: [SCOI2008]着色方案(巧妙的dp) 题意:有\(n\)个木块排成一行,从左到右依次编号为\(1\)~\(n\).你有\(k\)种颜色的油漆,其中第\(i\)种颜色的油漆足够涂\(c_i\)个木块.所有油漆刚好足够涂满所有木块,即\(\sum\limits _{i=1}^{k}c_i=n\).统计任意两个相邻木块颜色不同的着色方案.(\(1 \le k \le 15\) ,\(1\le c_i \le 5\)) 题解:特别巧妙的dp!一开始容易想到用\({c_i}^k

直接插入排序的两种做法

可能很多人不会留意到这个问题,今天恰好碰到了,然后来稍微讨论一下 直接插入排序应该是很多数据结构与算法书里第一个讲的排序算法,算法的描述是这样的: 把待排序列视作两段,一段是已排序列,一段是未排序列.每一趟排序时,为未排序列的首位在已排序列中进行查找(因为是直接插入排序,所以这里特指逐个比较)其合适的位置,然后将其插入(插入的过程中伴随着一系列元素的后移). 当时没有想太多,直接写了个按文字描述的代码: def InsertSort1(LIST): for i in range(1,len(LI

关于邻接矩阵的拆点 和一些杂七杂八想不到的做法

下午遇到了 LuoguP3597和LuoguP4159 这应该是我在网络流后第二次遇到的拆点.这两道题是结合邻接矩阵和拆点. 邻接矩阵有一个性质:设邻接矩阵A,则在矩阵Ak中,点aij的值表示从点i到j长度为k的通路数量.长度表示边的个数. P4159 要求的是:在有向图中,从起点到终点的路径权值和为k的路径数. 题目里,点的个数为n<=10,边的权值为1<=w<=9: 由于边的权值w很小,所以可以拆点,是边的权值为1,分为多条边.这样子就可以用邻接矩阵表示整个一阶有向图的连通关系. 所