zoukankan      html  css  js  c++  java
  • hdu6070(分数规划/二分+线段树区间更新,区间最值)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6070

    题意: 给出一个题目提交序列, 从中选出一个正确率最小的子串. 选中的子串中每个题目当且仅当最后一次提交是正确的.

    思路: 分数规划

    二分答案, 然后在 check 函数中查找是否存在某个区j间 [l, r] 使得 sum(l, r) / (r - l + 1) <= mid, 即 sum(l, r) + l * mid <= (r + 1) * mid. 可以用个线段树来维护 sum(l, r) + l * mid . 建树时直接将 l * mid 放入树中, 然后从左到右枚举 r, 对于当前 i, a[i] 对区间 [pre[i] + 1, i] 的贡献为一(区间 [1, pre[i]] 内的贡献之前的a[i]已经计算了) . 这样对于当前更新后, 1 <= j <= i , sum[j] 即为区间 [j, i] 内的贡献. 那么对于当前 i, query(1, i) 就得到了所有以 i 为后缀的区间的贡献最小值. 遍历完 r 后即得到了所有区间的贡献最小值.

    最后要注意一下线段树区间更新,区间最值的 lazy 数组维护写法, 最值和区间求和是不同的.

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define lson l, mid, rt << 1
     5 #define rson mid + 1, r, rt << 1 | 1
     6 using namespace std;
     7 
     8 const double eps = 1e-5;
     9 const int MAXN = 6e4 + 10;
    10 int a[MAXN], pre[MAXN], last[MAXN], n;
    11 double sum[MAXN << 2], lazy[MAXN << 2];
    12 
    13 void push_up(int rt){ //向上更新取最值
    14     sum[rt] = min(sum[rt << 1], sum[rt << 1 | 1]);
    15 }
    16 
    17 void push_down(int rt){
    18     if(lazy[rt]){//将标记向下更新,维护的是最值,sum不需要求和
    19         lazy[rt << 1] += lazy[rt];
    20         lazy[rt << 1 | 1] += lazy[rt];
    21         sum[rt << 1] += lazy[rt];
    22         sum[rt << 1 | 1] += lazy[rt];
    23         lazy[rt] = 0;
    24     }
    25 }
    26 
    27 void build(int l, int r, int rt, double value){
    28     lazy[rt] = 0;
    29     if(l == r){
    30         sum[rt] = value * l;
    31         return;
    32     }
    33     int mid = (l + r) >> 1;
    34     build(lson, value);
    35     build(rson, value);
    36     push_up(rt);
    37 }
    38 
    39 void update(int L, int R, int value, int l, int r, int rt){
    40     if(L <= l && R >= r){
    41         lazy[rt] += value;
    42         sum[rt] += value;//维护的是最值,sum不需要求和
    43         return;
    44     }
    45     push_down(rt);
    46     int mid = (l + r) >> 1;
    47     if(L <= mid) update(L, R, value, lson);
    48     if(R > mid) update(L, R, value, rson);
    49     push_up(rt);
    50 }
    51 
    52 double query(int L, int R, int l, int r, int rt){
    53     if(L <= r && R >= r) return sum[rt];
    54     push_down(rt);
    55     double cnt = 1e5;
    56     int mid = (l + r) >> 1;
    57     if(L <= mid) cnt = min(cnt, query(L, R, lson));
    58     if(R > mid) cnt = min(cnt, query(L, R, rson));
    59     return cnt;
    60 }
    61 
    62 bool check(double mid){
    63     build(1, n, 1, mid);
    64     for(int i = 1; i <= n; i++){
    65         update(pre[i] + 1, i, 1, 1, n, 1);
    66         if(query(1, i, 1, n, 1) <= (double)mid *(i + 1)) return true;
    67     }
    68     return false;
    69 }
    70 
    71 int main(void){
    72     int t;
    73     scanf("%d", &t);
    74     while(t--){
    75         scanf("%d", &n);
    76         memset(pre, 0, sizeof(pre));
    77         memset(last, 0, sizeof(last));
    78         for(int i = 1; i <= n; i++){
    79             scanf("%d", &a[i]);
    80             pre[i] = last[a[i]];
    81             last[a[i]] = i;
    82         }
    83         double l = 0, r = 1;
    84         while(r - l > eps){
    85             double mid = (l + r) / 2;
    86             if(check(mid)) r = mid - eps;
    87             else l = mid + eps;
    88         }
    89         printf("%.5lf
    ", r + eps);
    90     }
    91     return 0;
    92 }
    View Code
  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7298049.html
Copyright © 2011-2022 走看看