CSA Round #54 \(\ \)Voting

题目大意:

原题网址:戳我戳我!
一次歌唱比赛中,一位歌手刚刚结束表演,评委正在打分。
一共有 \(n\) 位评委,他们每人可以打 \(1\) 分或 \(0\) 分,第 \(i\) 位评委希望歌手的得分为 \(v[i]\)。
评委们有特殊的控分技巧,他们会按一个顺序依次评分,
第一个评分的评委会不管三七二十一打 \(0\) 分。
对于接下来的评委,假设前面 \(a\) 位评委评分总和为\(b\), 评委会认为这位歌手期望得分为 \(\frac{b}{a}n\),
如果这个得分低于他所希望的得分,他会打 \(1\) 分,否则他会打 \(0\) 分。
你希望选手的得分为 \(p\)\((0\leq p\leq n)\),为此你可以调换评委们的评分顺序。
你需要输出一个 \(1~n\) 的排列,第 \(i\) 个位置表示第 \(i\) 个评分的裁判的编号,让选手的得分最接近 \(p\)。
如果有多种,你只需要输出任意一种。

思路解法

假设裁判的期望得分是有序的,那么按编号顺序投票得分最大,按编号顺序倒序投票得分最小
这个非常的显然。证明之类的略。
然后我们可以发现一个至关重要的结论:

如果评分顺序中相邻两位裁判的期望得分为\(a\)和\(b\),
并且\(a\leq b\),那么交换这两位裁判,答案要么不变要么减少\(1\)

证明如下 , 一共分四种情况,假设原来:

  • a=0且b=0 ,交换后,a、b的前面状态未变,仍为0,答案不变。
  • a=1且b=0 ,交换后,b为1(比b怂的a在那里都为1),a的状态未知,答案不变或者减一。
  • a=0且b=1 ,交换后,b为1 且 a为0,b的前面状态未变,a在前面都是0到后面更不可能为1了,答案不变。
  • a=1且b=1 ,交换后,b为1显然,a的状态未知,答案不变或减一。
  • 综上所述,若\(a\leq b\),交换\(a\)与\(b\)后,答案不变或者减一。

考虑\(1\ 2\ 3\ 4\ 5\ ...\ n\)如何每次交换一个相邻的顺序对变成\(n\ n-1\ ...\ 2\ 1\) 。
其实与冒泡排序差不多:
\(1\ 2\ 3\ 4\) >>> \(1\ 2\ 4\ 3\) >>> \(1\ 4\ 2\ 3\) >>> \(4\ 1\ 2\ 3\) >>> \(4\ 1\ 3\ 2\ \)>>>\(4\ 3\ 1\ 2\)>>>\(4\ 3\ 2\ 1\)
由我们上面得到的结论可知,总分\(score\)是不断递减的。
设最大得分为\(Max\),最小得分为\(Min\)。
我们可以断定,如果\(p\in [Min,Max]\),那么一定是可以取到的。
所以我们二分上述交换进行了多少次,然后构造出此时的序列,计算出此时的分数继续处理即可。
如果无解,那么最终答案序列为最大或最小值序列中的一个。

实现代码

注:此题代码实现中,变换顺序与上述相反,为\(n\ ...\ 2\ 1\)变到\(1\ 2\ ... \ n\)。

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define ll long long
#define _ 500005
using namespace std;

ll pre[_] , stp[_] , n , p , f[_] , score;
struct Judger { ll v , id ; } q[_] ;  ll L , R , l , r; bool flag;

IL bool cmp(RG Judger A,RG Judger B){return A.v > B.v;}

IL int GetBlock(RG ll ps){
    l = 0 , r = n-1 ; RG ll res = -1;
    while(l <= r){
        RG ll mid = (l + r) >> 1;
        if(pre[ mid ] <= ps){res = mid; l = mid + 1;}
        else r = mid - 1;
    }return res;
}

IL ll Calc(){
    RG ll res = 0;
    for(RG ll i = 2; i <= n; i ++)
        if(res * n < (i-1) * q[f[i]].v)res ++;
    return res ;
}

IL void Rest(){
    for(RG ll i = 1; i <= n; i ++)f[i] = i;
    score = Calc();
    for(RG ll i = 1; i <= n; i ++)f[i] = n-i+1;
    if(abs(p - score) < abs(p - Calc()))
        for(RG ll i = 1; i <= n; i ++)f[i] = i;
    return;
}

IL void Build(RG ll mid){
    RG ll blk = GetBlock(mid),rest,t;
    for(RG ll i = 1; i <= blk; i ++)f[i] = i;
    rest = mid - pre[blk]; ++ blk;
    t = blk + 1;
    for(RG ll i = n; i >= n-rest+1; i --)f[i] = t ++;
    f[n - rest] = blk;
    for(RG ll i = n-rest-1; i >= blk; i --)f[i] = t ++;
}

int main(){
    cin >> n >> p;
    for(RG ll i = 1; i <= n; i ++)
        cin >> q[i].v  , q[i].id = i;
    sort(q + 1,q + n + 1,cmp);
    for(RG ll i = 1; i <= n; i ++)stp[i] = n - i;
    for(RG ll i = 1; i <= n; i ++)pre[i] = pre[i-1] + stp[i];
    flag = false;
    L = 0; R = n * (n-1) / 2;
    while( L <= R ){
        RG ll mid = (L + R) >> 1;
        Build(mid);
        score = Calc();
        if(score == p){flag = true; break;}
        else if(score < p)R = mid - 1;
        else L = mid + 1;
    }
    if(!flag)Rest();
    for(RG ll i = 1; i <= n; i ++)printf("%lld ",q[f[i]].id);
    return 0;
}

随机推荐

  1. Promise对象的简单用法

    要了解一个东西,首先要从,它是什么.用来做什么以及怎么取用它这三个方面来了解. 首先,promise是什么? 我们来参考一下MDN对它的定义: Promise 对象用于一个异步操作的最终完成(或失败) ...

  2. ThreadLocal 简述

    ThreadLocal的理解 Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们 ...

  3. String,StringBuffer,StringBuilder的区别

    数据结构: 数据结构是指相互之间存在一种或多种特定关系的数据元素的集合. 比如数据库就是对硬盘中的数据进行有规则的管理,可以进行增删改查工作,而良好的数据结构可以优化这些操作, 也许大家会想这些和St ...

  4. 数据库之mac上mysql root密码忘记或权限错误的解决办法

    [转自  http://blog.csdn.net/u014410695/article/details/50630233] 以下方法亲测有效,过程使用的工具只有mac的终端无需workbench 当 ...

  5. 如何为MySQL服务器和客户机启用SSL

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: mysql5.7后有ssl新特性 自己搭建mysql ent ...

  6. 删除apache注册表

    将Apache服务从系统服务中移除: 其实很多服务我们卸载软件后还会残留在服务列表里面,今天给大家提供个删除残留服务的方法注册表清除法. 1.在我的电脑上右键管理,找到看看那些服务是你不需要的,或是残 ...

  7. linux下安装jdk,tomcat以及mysql

    环境:centOS6.8.jdk1.8,tomcat-8.5.15,mysql-5.7.18 1.  安装JDK 注意:rpm与软件相关命令 相当于window下的软件助手 管理软件 步骤: 1)查看 ...

  8. C语言队列(数组内核)

    #include <stdio.h>#include <stdbool.h>#include <stdlib.h>struct Queue{ int *pBase; ...

  9. 1014. Waiting in Line (模拟)

    n个窗口就有n个队列,模拟这n个队列就可以了.需要注意的是,一个人在选择排队窗口的时候,他会选择排队人数最少的窗口,如果存在多个窗口排队的人数相同,那么他会选择编码最小的窗口. Note that s ...

  10. 为什么java局部变量没有初始化就会报错,而成员变量没有初始化就不会报错?

    代码如下 1.局部变量,报错!!! public void test(){ int i; System.out.println(i); } 2.成员变量,输出0 int i; @Test public ...