题面

在一个地区的选举中,共有V个人参加了投票,每一票只可能投给N个政党中的一个。当地的议会共有M个席位。不妨将N个政党编号为1到N,并且设编号为i的政党最终的得票为Vi,则议会中的席位按如下规则分配: 1、将得票数小于总选票的5%的政党剔除。 2、初始时议会为空,每个政党都只有0个席位。 3、对于每个政党P,计算一个参数Qp = Vp / (Sp + 1),Vp为政党P的最终得票,Sp为政党P当前已经在议会拥有的席位。 4、给Qp最大的政党分配一个席位,如果有多个政党的Qp相同,则将席位分给其中编号最小的政党。 5、重复3和4,直到议会已满。 由于计票还没有结束,现在我们只知道一部分选票的投票结果。给出V、N、M以及每个政党当前的得票,请你计算每个政党最多以及最少能赢得多少个席位。

题解

记剩下所有票数为sumsumsum。

xxx位置上的的最大值就是把sumsumsum全部给xxx,然后暴力枚举就行了。每次时间复杂度O(n2)O(n^2)O(n2),总时间复杂度O(n3)O(n^3)O(n3)。

下面是求xxx的最小值。方法是二分,假设二分的值是midmidmid,问题就转化为是否能让剩下的人凑足m−midm-midm−mid个席位。可以发现只有票数≥5%\geq 5\%≥5%的人才可能获得席位。所以只有票数前202020才可能获得席位。按贪心的思路,一定是从大到小排序后去前202020个来凑足m−midm-midm−mid个席位。

设f[i][j]f[i][j]f[i][j]表示用前iii个占领jjj个席位所需要的最少额外票数,那么转移为:

f[i][j]=min⁡k=0jf[i−1][j−k]+cost(i,k)f[i][j]=\min_{k=0}^jf[i-1][j-k]+cost(i,k)f[i][j]=k=0minj​f[i−1][j−k]+cost(i,k)cost(i,k)cost(i,k)cost(i,k)表示让第iii个位置的人占领kkk个席位所需要的最小票数。

要在xxx占领midmidmid个席位的情况下,让第iii个位置的人占领kkk个席位,需要满足的条件有:

  • (a[x]mid+1<a[i]k)(\frac{a[x]}{mid+1}< \frac{a[i]}{k})(mid+1a[x]​<ka[i]​) 或者 (a[x]mid+1=a[i]k&& i的编号<x的编号)(\frac{a[x]}{mid+1}= \frac{a[i]}{k}\&\&\ i的编号<x的编号)(mid+1a[x]​=ka[i]​&& i的编号<x的编号)
  • a[i]+cost(i,k)≥V∗5%a[i]+cost(i,k)\geq V*5\%a[i]+cost(i,k)≥V∗5%

那么直接转移就行了。每次时间复杂度O(20∗m2)O(20*m^2)O(20∗m2),总时间复杂度O(20∗m2log⁡m)O(20*m^2\log m)O(20∗m2logm)

CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline void rd(int &x) {
char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
x = 0; do x=x*10+ch-'0'; while(isdigit(ch=getchar())); x*=flg;
}
const int MAXN = 205;
int n, m, V, sum, a[MAXN], c[MAXN], id[MAXN];
inline bool cmp(int i, int j) { return a[i] > a[j]; }
int ans[MAXN], s[MAXN];
inline void Solve_mx() { //暴力枚举模拟
for(int i = 1; i <= n; ++i) {
a[i] += sum;
for(int j = 1; j <= n; ++j) s[j] = 0;
for(int j = 1; j <= m; ++j) {
int x = -1;
for(int k = 1; k <= n; ++k) if(a[k]*20 >= V) {
if(x == -1 || a[k]*(s[x]+1) > a[x]*(s[k]+1)) x = k;
}
if(~x) ++s[x];
}
printf("%d%c", s[i], " \n"[i==n]);
a[i] -= sum;
}
}
int f[21][MAXN];
inline bool check(int x, int mid) {
int cur = 0; for(int i = 0; i <= m; ++i) f[cur][i] = sum+1;
f[cur][0] = 0;
for(int i = 1; i <= n && i <= 20; ++i) {
if(i == x) continue; cur ^= 1;
for(int j = 0; j <= m; ++j) {
f[cur][j] = sum+1;
for(int k = 0; k <= j; ++k) {
int delta = (k * a[x] + mid) / (mid + 1) - a[i]; //向上取整
if(k * a[x] % (mid + 1) == 0 && id[x] < id[i] && k) ++delta; //判断在原数列编号大小
delta = delta < 0 ? 0 : delta;
if(k && (a[i]+delta)*20 < V) delta += (V - (a[i]+delta)*20 + 19) / 20; //凑足5%
f[cur][j] = min(f[cur][j], f[cur^1][j-k] + delta);
}
}
}
return f[cur][m-mid] <= sum;
}
inline int getmin(int x) {
if(a[x]*20 < V) return 0;
int l = 0, r = m, mid;
while(l < r) {
mid = (l + r) >> 1;
if(check(x, mid)) r = mid;
else l = mid+1;
}
return l;
} inline void Solve_mn() {
for(int i = 1; i <= n; ++i) id[i] = i, c[i] = a[i];
sort(id + 1, id + n + 1, cmp); //从大到小排序
for(int i = 1; i <= n; ++i) a[i] = c[id[i]];
for(int i = 1; i <= n; ++i) ans[id[i]] = getmin(i);
for(int i = 1; i <= n; ++i) printf("%d%c", ans[i], " \n"[i==n]);
}
int main () {
rd(V), rd(n), rd(m), sum = V;
for(int i = 1; i <= n; ++i) rd(a[i]), sum -= a[i];
Solve_mx();
Solve_mn();
}

BZOJ 1181: [CROATIAN2009] IZBROI选举(二分+dp)的更多相关文章

  1. 二分+DP HDU 3433 A Task Process

    HDU 3433 A Task Process Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  2. [BZOJ 4033] [HAOI2015] T1 【树形DP】

    题目链接:BZOJ - 4033 题目分析 使用树形DP,用 f[i][j] 表示在以 i 为根的子树,有 j 个黑点的最大权值. 这个权值指的是,这个子树内部的点对间距离的贡献,以及 i 和 Fat ...

  3. hdu 3433 A Task Process 二分+dp

    A Task Process Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  4. 2018.10.24 NOIP模拟 小 C 的数组(二分+dp)

    传送门 考试自己yyyyyy的乱搞的没过大样例二分+dp二分+dp二分+dp过了606060把我自己都吓到了! 这么说来乱搞跟被卡常的正解比只少101010分? 那我考场不打其他暴力想正解血亏啊. 正 ...

  5. 「学习笔记」wqs二分/dp凸优化

    [学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...

  6. 【bzoj1044】[HAOI2008]木棍分割 二分+dp

    题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且 ...

  7. Bzoj 1055: [HAOI2008]玩具取名 (区间DP)

    Bzoj 1055: [HAOI2008]玩具取名 (区间DP) 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1055 区间动态规划和可 ...

  8. Luogu P2511 [HAOI2008]木棍分割 二分+DP

    思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...

  9. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

随机推荐

  1. D2.Docker: 安装部署相关问题

    [mysql] docker 安装完mysql 后客户端无法访问

  2. [转帖]linux操作系统测试工具

    linux操作系统测试工具 http://cfdtesting.com/879156.html 作者: minions_222      来源: CFDTesting.com采编      发布于:  ...

  3. [SourceTree] - 使用内置 PuTTY 克隆项目出现 fatal: early EOF 问题之解决

    背景 使用 PuTTY 克隆 Asp.Net Core 项目失败. 错误 git -c filter.lfs.smudge= -c filter.lfs.required=false -c diff. ...

  4. Python35之包的创建

    包(package) 一.创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字 二.在文件夹中创建一个__init__.py的模块文件,内容可以为空 三将相关的模块放入文件夹中 这样就相当于创建 ...

  5. 【Linux】一步一步学Linux——Linux发展史(01)

    目录 00. 目录 01. Linux概述 02. Linux简史 03. Linux主要特性 04. Linux之父 05. Linux相关术语 06. Linux其它 07. Linux应用领域 ...

  6. 【转载】Maven入门实践

    Maven 确确实实是个好东西,用来管理项目显得很方便,但是如果是通过 Maven 来远程下载 JAR 包的话,我宿舍的带宽是4兆的,4个人共用,有时候用 Maven 来远程下载 JAR 包会显得很慢 ...

  7. HttpClient 远程接口调用方式

    远程接口调用方式HttpClient 问题:现在我们已经开发好了接口了,那该如何调用这个接口呢? 答:使用Httpclient客户端.   Httpclient简介 什么是httpclient Htt ...

  8. oracle_job进程相关学习测试

    Oracle cjq0进程测试 测试流程: .CJQ进程不存在 .模拟问题处理 .问题总结 一.问题现象 CJQ0进程不存在 [root@adg1 ~]# ps -ef|grep cjq root : ...

  9. kafka的安装及使用(单节点)

    介绍了linux环境下,kafka 服务的安装与配置 安装 jdk 环境 下载 kafka 源码包放到服务器,解压 开启 zookeeper 开启 kafka server 创建主题 开启生产者 开启 ...

  10. ECMAScript5面向对象技术(2)--函数

    在JavaScript中,函数其实就是对象.使函数不同于其他对象的决定性特点是函数存在一个被称为[[Call]]的内部属性.内部属性无法通过代码访问而是定义了代码执行时的行为.ECMAScript为J ...