ACM 算法艺术与信息竞赛 1.2.6 离散函数

这个题,如果认真看了题意就比较明白了。这里我直接引用百度上的博客


1010. Discrete Function

题目描述:

有一个函数,它的定义域:1 to N(2<=N<=100000),值域f(n)long int(in C++)(最后证明在-2^31—2^31)。要求函数上的两个点a,b使得当x∈(a,b)函数f,在直线ab的下方,并且要求ab的倾角最大。

分析:

解法一:一开始只想到O(n^2)的解法,对于每个点,穷举剩下的点与之连成一条直线,然后判别是否满足题目条件。

解法二:在<<算法艺术与信息学竞赛>>(黑书)上提示还有O(n)的解法,想了很久,没有想出来,反而把问题复杂化(做事最忌讳这点):)。后来参考了题目下的讨论,发现这个题目有一个特点:如果两个点满足题目条件的话,那么这两点一定是相邻的点。假设这个命题成立的话,我们只要计算相邻两点的倾角,最大的就是题目的答案。时间复杂度O(n)

接下来我们用反证法来证明这一结论:

首先,我们假设命题不成立,即,存在一个解,ab的倾角最大,但ab不相邻。

那么,ab一定存在一点x,使得xb在函数的上方。如图:

从图中可以看出ab不是倾角最大的,xb的倾角比ab大,从而得出矛盾,即证明了,倾角最大的两个顶点一定相邻。(自己开始也不太相信,太不可思议了!)

最后注意函数f的取值范围,选择适当的类型进行计算。

我参考了:http://www.cppblog.com/Hero/archive/2008/10/13/63867.aspx上的解法,用double类型来做。


这个题如果用int来做,会错掉,我是干脆直接用double来写了。

#include<stdio.h>
#include<stdlib.h>
#define abs(a)  ((a) > 0 ? (a) : 0 - (a))

double a[100001], mx = 0, v;
int i, mx_iter, n;
int main(void)
{
	while (scanf("%d", &n) != EOF)
	{
		for (i = 0; i < n; ++i) scanf("%lf", a + i);
		mx = 0;
		for (i = 0; i < n - 1; ++i)
		{
			v = abs(a[i+1] - a[i]);
			if (v > mx) { mx = v; mx_iter = i;}
		}
		i = mx_iter + 1;
		printf("%d %d\n", i, i + 1);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值