这个题,如果认真看了题意就比较明白了。这里我直接引用百度上的博客
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的倾角最大,但a与b不相邻。
那么,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; }