码迷,mamicode.com
首页 > Web开发 > 详细

GDOI#345. 送礼物「JSOI 2015」01分数规划+RMQ

时间:2019-08-31 23:16:59      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:最大   list   ade   size   att   header   print   ||   res   

题目描述

JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物。萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成一列,而且相邻的礼物之间有一种神秘的美感。于是,JYY决定从中挑选连续的一些礼物,但究竟选哪些呢?假设礼品店一共有N件礼物排成一列,每件礼物都有它的美观度。排在第i(1\leq i\leq N1iN)个位置的礼物美观度为正整数A_iAi?。JYY决定选出其中连续的一段,即编号为礼物i,i+1,…,j-1,ji,i+1,,j1,j的礼物。选出这些礼物的美观程度定义为:

(M(i,j)-m(i,j))/(j-i+k)(M(i,j)m(i,j))/(ji+k),其中M(i,j)M(i,j)表示max\{A_i,A_{i+1}....A_j\}max{Ai?,Ai+1?....Aj?},m(i,j)m(i,j)表示min\{A_i,A_{i+1}....A_j\}min{Ai?,Ai+1?....Aj?},K为给定的正整数。

由于不能显得太小气,所以JYY所选礼物的件数最少为L件;同时,选得太多也不好拿,因此礼物最多选R件。JYY应该如何选择,才能得到最大的美观程度?由于礼物实在太多挑花眼,JYY打算把这个问题交给会编程的你。

法一:用单调暴力求解,然后你就可以得到宝贵的20分(本人亲自实验)。

法二(正解):

若区间长度等于规定L,就直接用单调队列维护长度为L的区间的最大值和最小值,分别计算每个区间,用一个ans记录最大值。

若区间大于L,对于一个区间[l, r]很明显可以发现最优的取法是在A[l]为最小值, A[r]为最大值或A[l]为最小值,A[r]为最大值。

然后开始二分答案。

judge函数:

1, A[l] > A[r], 要A[l] - A[r] > (r - l + 1) * mid; 所以若max{A[i] + i * mid - (A[j] - j * mid) - k * mid} >= 0则mid可以更大

2,若A[l] < A[r] 同理,反过来就行。

所有A[i] + i * mid, A[j] - j * mid用单调队列来维护。

#include <bits/stdc++.h>
using namespace std;
const long long MAX = 500005;
const double INF = 1e9;
long long t, n, k, l, r;
long long a[MAX], q1[MAX], q2[MAX], q[MAX];
double val[MAX];
double ans;
//读入优化 
double read() {
    double ret = 0, f = 1;
    char ch = getchar();
    while (0 > ch || ch > 9) {
        if (ch == -) f = -1;
        ch = getchar();
    }
    while (0 <= ch && ch <= 9) {
        ret = ret * 10 + ch - 0;
        ch = getchar();
    }
    return ret * f;
}
//判断 
bool judge(double m) {
    double ret = -INF;
    for (long long i = 1; i <= n; i++) {
        val[i] = a[i] - m * i;
    }
    long long head = 1, tail = 0;
    for (long long i = l + 1; i <= n; i++) {
        while (head <= tail && i - q[head] >= r) head++;
        while (head <= tail && val[q[tail]] >= val[i - l]) tail--;
        q[++tail] = i - l;
        ret = max(ret, val[i] - val[q[head]]);
    }
    for (long long i = 1; i <= n; i++) {
        val[i] = a[i] + m * i;
    }
    head = 1, tail = 0;
    for (long long i = n - l; i >= 1; i--) {
        while (head <= tail && q[head] - i >= r) head++;
        while (head <= tail && val[q[tail]] >= val[i + l]) tail--;
        q[++tail] = i + l;
        ret = max(ret, val[i] - val[q[head]]);
    }
    //k是题目给的常数 
    return ret >= k * m;
}
int main() {
    t = read();
    while (t--) {
        ans = -INF;
        n = read(), k = read(), l = read(), r = read();
        for (long long i = 1; i <= n; i++) a[i] = read();
        long long h1 = 1, h2 = 1, t1 = 0, t2 = 0;
        for (long long i = 1; i < l; i++) {
            while (h1 <= t1 && a[q1[t1]] >= a[i]) t1--;
            while (h2 <= t2 && a[q2[t2]] <= a[i]) t2--;
            q1[++t1] = q2[++t2] = i; 
        }
        for (long long i = 1; i <= n; i++) {
            while (h1 <= t1 && i - q1[h1] >= l) h1++;
            while (h2 <= t2 && i - q2[h2] >= l) h2++;
            while (h1 <= t1 && a[q1[t1]] >= a[i]) t1--;
            while (h2 <= t2 && a[q2[t2]] <= a[i]) t2--;
            q1[++t1] = q2[++t2] = i;
            ans = max(ans, 1.0 * (a[q2[h2]] - a[q1[h1]]) / (l + k - 1));
        }
        //注意精度 
        double l = 0, r = 1000;
        while (r - l >= 0.000001) {
            double mid = (l + r) / 2;
            if (judge(mid)) ans = max(ans, mid), l = mid + 0.000001;
            else r = mid - 0.000001;
        }
        printf("%.4lf\n", ans);
    }
    return 0;
}

 

GDOI#345. 送礼物「JSOI 2015」01分数规划+RMQ

标签:最大   list   ade   size   att   header   print   ||   res   

原文地址:https://www.cnblogs.com/zcr-blog/p/11440760.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!