hdu 2993

这个应该就是斜率优化了。(由于用到单调队列,好像也有叫单调队列优化的)

题目的意思很简单,给出N个正整数,求最大的,长度大于K的某一段的平均值。设部分和数组为S,则容易得到方程 (S[j]-S[i-1])/(j-i+1),这可以看做(i,S[i])和(j,S[j])的斜率,那么问题转化为求n个点中水平距离至少为k的最大斜率。

#include<stdio.h>
#define LL long long
typedef struct
{
    int x,y;
}Node;
Node pp[100010];
Node tmp,now; double res; int sum[100010]; int head,tail;
LL multi(Node a,Node b,Node c)
{
    return (LL)(b.x-a.x)*(c.y-a.y) - (LL)(b.y-a.y)*(c.x-a.x) ;
}
void read(int &r) {
    char c;
    while (c = getchar(), c < '0' || c > '9');
    r = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0';
}
int main()
{
    int n,k,i,j; double tt;
    while(~scanf("%d%d",&n,&k))
    {
        sum[0]=0; head=tail=0; tt=res=0.0;
        for(i=1;i<=n;i++)
        {
            read(sum[i]);      //为什么要卡这个,我搞不清楚
            sum[i]+=sum[i-1];
        }
        for(i=k;i<=n;i++)
        {
            tmp.x=i-k;
            tmp.y=sum[i-k];      //对于每个新的点(i,sum[i]),会有新的点tmp要考虑是否加入到队列里
            while( tail-head>=2 && multi(pp[tail-2],pp[tail-1],tmp)<=0 )  //判断新的点是否是当前凸包的点,是的话,去掉多余的点(tail--)
                tail--;
            pp[tail]=tmp; tail++;          //加入新的点
            now.x=i; now.y=sum[i];
            while(tail-head>=2 && multi(pp[head],pp[head+1],now)>=0 )    // 这句话是要找到点p(i,sum[i])与折线的切点q( 切点的特征是K(q左边的点,q) < K(p,q) < K(q,q右边的点)  ) 所以说p与q的斜率在一个固定的范围内,这个范围与点q有关。  至于为什么要把q前面的点删除呢,是因为下凸线的斜率是递增的,如果存在点S(s,sum[s])(s>i),S与折线的切点是q点之前的某个点T的话,那么 K(S,T)的斜率肯定小于K(q,p);为什么?前面已经解释了,是因为下凸线斜率的单调递增的性质决定的;所以说q点前的点都可以删除; 
                head++;
            tt=(double)(now.y-pp[head].y)/(now.x-pp[head].x);
            res= tt>res?tt:res;
        }
        printf("%.2lf\n",res);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值