[HDU2993]MAX Average Problem

4 篇文章 0 订阅

题目链接HDU2993

题目大意
给定一个正整数数列和 K ,定义ave(i,j) a[i]...a[j] 的平均数,求最大 ave(i,j),Kji+1

分析
1. 定义 S[i] 为前 i 项和,即求max((S[i]S[j])/(ij)),即找坐标系中两点斜率最大。
2. 定义 dp[i] 为以 i 结束的合法子段,dp[i]=max((S[i]S[j])/(ij)),jA,A为合法解集。
3. 处理 dp[i] 之前把 ik 推进 A ,并维护A的下凸性质,查找最优解时可以二分找到切点, O(logN)

优化
1. 考虑当前 dp[i] A 中切点为j,那么对于 A 中在j之前的点 q ,即使成为某个决策的切点,斜率也不会比当先前最优解大;即维护A中最先面的点为当切点,均摊 O(1)
2. 此题卡读入,貌似连普通的读入优化也没用,只有用 fread 啦。
ps. 非常感谢 UOJ 上某 dalao fread 模板,贸然取用,不要见怪啊。
终于把图给补了
UPD:终于把图给补了

上代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef double DB;
typedef long long LL;
const int N = 1e5 + 10;

int n, m;
LL sum[N];

namespace io //高级读入歪瓜
{
    const int MAXBUF = 1 << 22;
    char B[MAXBUF], *S = B, *T = B;
    #define getc() (S == T && (T = (S = B) + fread(B, 1, MAXBUF, stdin), S == T) ? 0 : *S++)
    template<class Type> inline Type read()
    {
        register Type aa = 0;
        register bool bb = 0;
        register char ch, *S = io::S, *T = io::T;
        for(ch = getc(); (ch < '0' || ch > '9') && ch != '-'; ch = getc())
            if (! ch) exit(0);
        for(ch == '-' ? bb = 1 : aa = ch - '0', ch = getc(); '0' <= ch && ch <= '9'; ch = getc())
            aa = aa * 10 + ch - '0';
        io::S = S, io::T = T;
        return bb ? -aa : aa;
    }
    int (*F)() = read<int>;

    template<> inline double read()
    {
        register double aa, bb;
        register char ch;
        register char *S = io::S, *T = io::T;
        while(ch=getc(),(ch<'0'||ch>'9'))
            ;aa=ch-'0';
        while(ch=getc(),(ch>='0'&&ch<='9'))aa=aa*10+ch-'0';
        if(ch=='.'){bb=1;while(ch=getc(),ch>='0'&&ch<='9')bb*=0.1,aa+=bb*(ch-'0');}
        io::S = S, io::T = T;
        return aa;
    }

    char buff[MAXBUF], *iter = buff;
    template<class T>inline void P(register T x, register char ch = '\n')
    {
        static int stack[110];
        register int O = 0;
        register char *iter = io::iter;
        if(!x)*iter++ = '0';
        else
        {
            (x < 0) ? x = -x, *iter++ = '-' : 1;
            for(; x; x /= 10)
                stack[++O] = x % 10;
            for(; O; *iter++ = '0' + stack[O--])
                ;
        }
        *iter++ = ch, io::iter = iter;
    }

    inline void putc(register char ch) {*iter++ = ch;}

    inline void output() {fwrite(buff, 1, iter - buff, stdout), iter = buff;}
}

struct nodeQ {
    int head, tail, val[N];
    void pop_front() { head++; }
    void pop_back() { tail--; }
    void clear() { head = tail = 0; }
    int size() { return tail - head; }
    void push_back(int a) {val[tail++] = a; }
    int back(int a) { return val[tail - a]; }
    int front(int a) { return val[head + a - 1]; }
} Q;

#define Nu(a, b) (sum[a] - sum[b])
#define De(a, b) (a - b)
inline DB calcK(int a, int b) {
    return (DB)Nu(a, b) / De(a, b);
}
inline bool judge(int a, int b, int c, int d) {
    return Nu(a, b) * De(c, d) <= Nu(c, d) * De(a, b);
}
int main() {
    int (*F)() = io::read<int>;
    while (1) {
        n = F(); m = F();
        DB maxn = 0;
        Q.clear();
        for (int i = 1; i <= n; i++)
            sum[i] = F() + sum[i - 1];
        for (int i = m; i <= n; i++) { //斜率优化,维护解集下凸且第一个点为合法最优解
            int tmp = i - m;
            while (Q.size() >= 2 && judge(tmp, Q.back(1), Q.back(1), Q.back(2)))
                Q.pop_back();
            Q.push_back(tmp);
            while (Q.size() >= 2 && judge(i, Q.front(1), i, Q.front(2)))
                Q.pop_front();
            maxn = max(maxn, calcK(i, Q.front(1)));
        }
        printf("%.2lf\n", maxn);
    }
    return 0;
}

以上

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值