zoukankan      html  css  js  c++  java
  • 【BZOJ】4985: 评分【DP】

    4985: 评分

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 148  Solved: 75
    [Submit][Status][Discuss]

    Description

    Lj最近参加一个选秀比赛,有N个评委参加了这次评分,N是奇数。评委编号为1到N。每位评委给Lj打的分数是一个
    整数,评委i(1 ≦ i ≦ N)的打分为Di。这次采用了一种创新的方法计算最后得分,计算规则是:最初N位评委排
    成一排,检查队伍排头的3位评委的评分,去掉一个最高分和一个最低分,剩下的一个评委移动到队伍最后,反复
    执行以上操作,直到队伍中的评委只剩一位,那么这个评委的打分就是Lj的最后得分。由于有的评委年纪比较大了
    ,不记得自己的位置了,现在有M(1 ≦ M ≦ N - 2)个评委很快找到了自己的位置,剩下的N-M人找不到位置了,
    需要给他们重新安排位置。
    由于Lj希望自己的得分尽可能高。请你帮忙计算出LJ最后得分可能的最大值。

    Input

    第一行为整数N和M,用空格分隔。表示有N位评委,其中M人的初始排列位置已经确定。
    接下来M行中第i行(1 ≦ i ≦ M)为两个整数Di和Pi,用空格分隔。
    表示第i位评委的评分为Di,初始排列位置为队伍排头开始的第Pi位。
    接下来N-M行中第i行(1 ≦ i ≦ N ? M)为整数Di+M,表示评委(i+M)的评分为Di+M。
    3 ≦ N ≦ 99 999,
    1 ≦ M ≦ N - 2,
    1 ≦ Di ≦ 109 (1 ≦ i ≦ N),
    1 ≦ Pi ≦ N (1 ≦ i ≦ M),
    Pi != Pj (1 ≦ i < j ≦ M)。

     

    Output

     输出一行,为1个整数,表示LJ得分的最大值。

    Sample Input

    7 3
    5 2
    5 5
    8 6
    6
    2
    8
    9

    Sample Output

    8
    //最高得分的评分排列:2, 5, 6, 8, 5, 8, 9

    Solution

    这道题太巧妙了丫!

    核心思想是二分+dp统计答案。

    如何判断答案是否合法?我们的目的是让最后剩下的那个大于等于二分的$mid$。用一个$f[i]$表示让前$n$个第$i$个位置合法,之前最少需要多少个剩下$n-m$个中合法的但不确定的来补。

    所以一开始如果是确定的并且$>=mid$,那么$f$值是0,如果确定但$<mid$,$f$值是inf。如果不确定,那么就是1(在这个位置放一个合法的)

    把以上按顺序放到一个队列里,然后模拟删除操作即可。因为我们要使转移后的也合法,那么每次三个中至少有两个合法(最高的和它自己),所以每次在队列前三个中两两和取$min$入队即可。(转移当前需要至少多少个来补)

    最后判断一下最后剩下的这个$f$是不是小于等于不确定位置中符合条件的数量即可。

    Code

    #include<bits/stdc++.h>
    #define oo 0x3f3f3f3f
    using namespace std;
    
    int b[100005], G[100005], n, m;
    bool check(int mid) {
        queue < int > q;
        int tot = 0;
        for(int i = 1; i <= n - m; i ++)    if(b[i] >= mid)    tot ++;
        for(int i = 1; i <= n; i ++) {
            if(!G[i])    q.push(1);
            else if(G[i] >= mid)    q.push(0);
            else         q.push(oo);
        }
        while(q.size() > 1) {
            int x1 = q.front(); q.pop();
            int x2 = q.front(); q.pop();
            int x3 = q.front(); q.pop();
            q.push(min(min(x1 + x2, x1 + x3), min(x2 + x3, oo)));
        }
        if(q.front() <= tot)    return 1;
        return 0;
    }
    
    int erfen() {
        int l = 0, r = oo, ans;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid))    ans = mid, l = mid + 1;
            else            r = mid - 1;
        }
        return ans;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i ++) {
            int a, b;
            scanf("%d%d", &a, &b);
            G[b] = a;
        }
        for(int i = 1; i <= n - m; i ++)    scanf("%d", &b[i]);
        int ans = erfen();
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    console.time测试代码块执行时间
    label表单的关联性
    attr返回被选元素的属性值
    2018 885程序设计编程题
    输出斐波拉数列的前n个数(n>=2)
    简单的光照贴图
    复杂纹理复制及纹理叠加效果
    简单纹理复制
    UV旋转shader
    shader实现积雪效果
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9778889.html
Copyright © 2011-2022 走看看