一 定义
利用图像的凹凸性解决一些数学问题,如查找最大的斜率。
二 例题
其实我们可以知道这道题其实就是求在长度为 [ s , t ] [ s, t] [s,t] 的子段内的最大斜率
三 解决思路
以上面这个图中,我们可以发现p2点是一个凸点, y 2 − y i x 2 − x i > y i − y t x i − x t \frac{y_{2}-y_{i}}{x_{2}-x_{i}} > \frac{y_{i}-y_{t}}{x_{i}-x_{t}} x2−xiy2−yi>xi−xtyi−yt ,任何一个 p i p_{i} pi 都不能和 p 2 p_{2} p2 一起形成一个最优解,其他的点总是能和 p 3 p_{3} p3 一起形成最优解,所以此时这个 p 2 p_{2} p2 就能被我们删除出待选的点中
而判断这个凸点的方法就是判断 k ( p i − p k ) > k ( p i − p k + 1 ) k(p_{i} - p_{k}) > k(p_{i}-p_{k+1}) k(pi−pk)>k(pi−pk+1),这样的话我们就可以判断这个k点就是凸点,可以直接删除
四 code
#include<iostream>
#define N 100100
using namespace std;
int n,s,t,x,l,a[N],q[N];
double decline(int x,int y)
{
return 1.0*(a[y]-a[x])/(y-x);
}
int main()
{
scanf("%d%d%d",&n,&s,&t);
for(int i = 1;i <= n;i++)
{
scanf("%d",&x);
a[i] = a[i-1] + x;
}
double ans = 0;
int head =0 ,tail = 0;
q[tail++] = 0;
for(int i = s;i <= n;i++)
{
while(head + 1 < tail&&(decline(q[head],i) < decline(q[head + 1],i)||i - q[head] + 1 > t)) head++;
// 消除上凸点,得到全部都是下凹的曲线
ans = max(ans, decline(q[head],i));
// 更新ans
int j = i - s + 1;
// 可行的边界点
while(head + 1 < tail &&decline(q[tail-1],j) < decline(q[tail - 2],q[tail - 1])) tail--;
// 我们删除那些加入边界点后不可行的点
q[tail++] = j;
}
printf("%.3lf",ans);
}