Codeforces C. Elections(贪心枚举三分)
题目描述:
C. Elections
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
As you know, majority of students and teachers of Summer Informatics School live in Berland for the most part of the year. Since corruption there is quite widespread, the following story is not uncommon.
Elections are coming. You know the number of voters and the number of parties — nn and mm respectively. For each voter you know the party he is going to vote for. However, he can easily change his vote given a certain amount of money. In particular, if you give ii-th voter cici bytecoins you can ask him to vote for any other party you choose.
The United Party of Berland has decided to perform a statistical study — you need to calculate the minimum number of bytecoins the Party needs to spend to ensure its victory. In order for a party to win the elections, it needs to receive strictly more votes than any other party.
Input
The first line of input contains two integers nn and mm (1≤n,m≤30001≤n,m≤3000) — the number of voters and the number of parties respectively.
Each of the following nn lines contains two integers pipi and cici (1≤pi≤m1≤pi≤m, 1≤ci≤1091≤ci≤109) — the index of this voter's preferred party and the number of bytecoins needed for him to reconsider his decision.
The United Party of Berland has the index 11.
Output
Print a single number — the minimum number of bytecoins needed for The United Party of Berland to win the elections.
Examples
input
Copy
1 2
1 100
output
Copy
0
input
Copy
5 5
2 100
3 200
4 300
5 400
5 900
output
Copy
500
input
Copy
5 5
2 100
3 200
4 300
5 800
5 900
output
Copy
600
Note
In the first sample, The United Party wins the elections even without buying extra votes.
In the second sample, The United Party can buy the votes of the first and the fourth voter. This way The Party gets two votes, while parties 33, 44 and 55 get one vote and party number 22 gets no votes.
In the third sample, The United Party can buy the votes of the first three voters and win, getting three votes against two votes of the fifth party.
思路:
刚开始:拿到题的时候思路非常混乱,一直想着贪心的做,想找出一种决策可以在每一步最优的情况下得到全局最优。可是试了几种决策后发现不是很恰当,还曾一度以为只要1党的票数高过总票数的一半就可以胜出。事实证明,是可以胜出,但不是最优。
看来直接贪心不太容易,怎么办呢?
首先想到我们不知道1党要得到多少票才能获胜,直接的想法是枚举这个票数k,最少1票最多n票,1党的票数要大于等于k,要使1党获胜,那其他党的票数就要小于k。算出每个k对应的最小花费的最小值,就是最终答案,时间复杂度为O(\(n^2\))。
实现方式有两种,第一种是以每个选民为着眼点,把选民按照收买价格从小到大排序(贪心的思想),用一个数组记录每个党的得票数,遍历选民只要改选民的党的票数\(\geq\)k,就收买这个选民,对应的这个党的票数就会减一,1党票数就会加一,并给选民做上标记,遍历完后如果1党票数\(\geq\)k,就算出这个k下的结果,如果还不够,就再遍历一遍,收买未收买的选民直到满足条件。
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt[max_n];
int check[max_n];
struct node
{
int f;
long long mon;
};
node a[max_n];
int cnta = 0;
int cmp(node a,node b)
{
return a.mon<b.mon;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
a[cnta].f = party;
a[cnta].mon = money;
cnta++;
cnt[party]++;
check[party] = 0;
}
}
sort(a,a+cnta,cmp);
for(int k = 1;k<=n;k++)
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
memset(cnt,0,sizeof(cnt));
for(int i = 0;i<cnta;i++)
{
cnt[a[i].f]++;
}
for(int i = 0;i<=cnta;i++)
{
if(cnt[a[i].f]>=k)
{
total += a[i].mon;
cnt[a[i].f]--;
check[i] = 1;
s++;
}
}
if(s>=k)
{
minm = min(minm,total);
}
else
{
for(int i = 0;s<k;i++)
{
if(check[i]==0)
{
total += a[i].mon;
s++;
}
}
if(minm>total)
{
minm = total;
}
}
}
cout << minm << endl;
return 0;
}
还有一种以党为着眼点,用一个结构体vector数组记录每个党的选民投票情况,当然也要排序,思路也是枚举,只不过实现稍复杂一点。
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt = 0;
struct node
{
int id;
long long m;
};
node a[max_n];
int check[max_n];
struct voter
{
int id;
int mon;
};
vector<voter> pai[max_n];
int cmp(voter a,voter b)
{
return a.mon<b.mon;
}
int cmp2(node a,node b)
{
return a.m < b.m;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
voter v;
v.id = cnt;
v.mon = money;
a[cnt].id = cnt;
a[cnt].m = money;
cnt++;
pai[party].push_back(v);
}
}
for(int i = 2;i<=m;i++)
{
sort(pai[i].begin(),pai[i].end(),cmp);
}
sort(a,a+cnt,cmp2);
for(int k = 1;k<=n;k++)
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
for(int i = 2;i<=m;i++)
{
for(int j = 0;pai[i].size()-j>=k;j++)
{
total += pai[i][j].mon;
check[pai[i][j].id] = 1;
s++;
}
}
if(s>=k)
{
minm = min(minm,total);
}
else
{
for(int i = 0;s<k;i++)
{
if(check[a[i].id]==0)
{
total += a[i].m;
s++;
}
}
if(minm>total)
{
minm = total;
}
}
}
cout << minm << endl;
return 0;
}
实际上,这个k为自变量,收买价格为因变量是一个下凸函数,在1~n里有一个最小值,可以用三分的方法求极小值点。(关于三分的讲解见参考文章)
代码:
#include <iostream>
#include <algorithm>
#include <memory.h>
#include <climits>
#define max_n 3005
using namespace std;
int sum = 0;
long long total = 0;
long long minm = LLONG_MAX;
int m;
int n;
int cnt[max_n];
int check[max_n];
struct node
{
int f;
long long mon;
};
node a[max_n];
int cnta = 0;
int cmp(node a,node b)
{
return a.mon<b.mon;
}
long long cal(long long k)//相当于计算函数值,将版本一中的计算每种花费的情况独立成一个函数
{
int s = sum;
total = 0;
memset(check,0,sizeof(check));
memset(cnt,0,sizeof(cnt));
for(int i = 0; i<cnta; i++)
{
cnt[a[i].f]++;
}
for(int i = 0; i<=cnta; i++)
{
if(cnt[a[i].f]>=k)
{
total += a[i].mon;
cnt[a[i].f]--;
check[i] = 1;
s++;
}
}
if(s>=k)
{
//cout << "sum>=k" << endl;
return total;
}
else
{
//cout << "sum<k" << endl;
for(int i = 0; s<k; i++)
{
if(check[i]==0)
{
total += a[i].mon;
s++;
}
}
}
return total;
}
int main()
{
cin >> n >> m;
for(int i = 0;i<n;i++)
{
int party;
long long money;
cin >> party >> money;
if(party==1)
{
sum += 1;
}
else
{
a[cnta].f = party;
a[cnta].mon = money;
cnta++;
cnt[party]++;
check[party] = 0;
}
}
sort(a,a+cnta,cmp);
int l = 1;
int r = n;
while(r-l>3)//最后选出三个可能的极小值点
{
int mid = (l+r)>>1;
int mmid = (mid+r)>>1;
long long sum1 = cal(mid);
long long sum2 = cal(mmid);
if(sum1>sum2)//mmid更接近于极小值点
{
l = mid;
}
else//mid更接近于极小值点
{
r = mmid;
}
}
minm = cal(l);
for(int i = l+1;i<=r;i++)
{
long long ans = cal(i);
minm = min(minm,ans);
}
cout << minm << endl;
return 0;
}
参考文章:
键盘里的青春,三分算法概念,https://blog.csdn.net/qq_34374664/article/details/70141246
henuzxy,codeforces 1019 A. Elections (枚举或三分),https://blog.csdn.net/zhao5502169/article/details/81625471
闻道-问道,C. Elections(枚举+贪心),https://blog.csdn.net/a1046765624/article/details/81876925
Codeforces C. Elections(贪心枚举三分)的更多相关文章
- CodeForces - 1020C C - Elections(贪心+枚举)
题目: 党派竞争投票 有n个人,m个党派,这n个人每个人有一个想要投的党派的编号Pi,如果想要这个人改变他的想法,那么就需要花费Ci元钱. 现在你是编号为1的党派,如果你想要赢(你的票数严格大于其他党 ...
- 【BZOJ3874】[AHOI&JSOI2014]宅男计划(贪心,三分)
[BZOJ3874][AHOI&JSOI2014]宅男计划(贪心,三分) 题面 BZOJ 洛谷 题解 大力猜想一最长的天数和购买外卖的总次数是单峰的.感性理解一下就是买\(0\)次是\(0\) ...
- Codeforces 458C - Elections
458C - Elections 思路: 三分凹形函数极小值域 代码: #include<bits/stdc++.h> using namespace std; #define ll lo ...
- codeforces 578c - weekness and poorness - 三分
2017-08-27 17:24:07 writer:pprp 题意简述: • Codeforces 578C Weakness and poorness• 给定一个序列A• 一个区间的poornes ...
- CodeForces - 158B.Taxi (贪心)
CodeForces - 158B.Taxi (贪心) 题意分析 首先对1234的个数分别统计,4人组的直接加上即可.然后让1和3成对处理,只有2种情况,第一种是1多,就让剩下的1和2组队处理,另外一 ...
- POJ 1018 Communication System 贪心+枚举
看题传送门:http://poj.org/problem?id=1018 题目大意: 某公司要建立一套通信系统,该通信系统需要n种设备,而每种设备分别可以有m个厂家提供生产,而每个厂家生产的同种设备都 ...
- Codeforces Round #503 (by SIS, Div. 2) C. Elections(枚举,暴力)
原文地址 C. Elections time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- codeforces 613B B. Skills(枚举+二分+贪心)
题目链接: B. Skills time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
- 【codeforces 761C】Dasha and Password(贪心+枚举做法)
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
随机推荐
- Angular2 输入完成后触发函数
(blur)="keySearch($event)" ,鼠标点击其他地方触发 keySearch(e): void { var dom = $(e.target); var key ...
- windows mysql手动添加my.ini 服务启动不了
[mysqld] character-set-server=utf8 #绑定IPv4和3306端口 bind-address=0.0.0.0 port= default_storage_engine= ...
- Spark学习(2) RDD编程
什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.弹性.里面的元素可并行计算的集合 RDD允 ...
- logstash解析tomcat的catalina.out日志字段
filter { mutate { remove_field => ["@version","prospector","input", ...
- 阿里巴巴 Java 开发手册 (十二)安全规约
1. [强制]隶属于用户个人的页面或者功能必须进行权限控制校验. 说明:防止没有做水平权限校验就可随意访问.修改.删除别人的数据,比如查看他人的私信 内容.修改他人的订单. 2. [强制]用户敏感数据 ...
- Golang_小程序学golang
1 前置条件 Golang基本情况自行baidu/google 1.1 环境与工具 IDE:liteide (windows ).mingw-w64 (gcc) DB:SQL Server 2008 ...
- 在Java中如何设置一个定时任务,在每天的一个时间点自动执行一个特定的程序
Quartz定时机制 首先导入jar包到程序内 quartz-all-1.6.0.jar 然后创建一个XML TimeConfig.xml 名字可以自己定义 <?xml version=&quo ...
- 深入理解JVM(三) -- 对象的内存布局和访问定位
一 对象的内存布局: 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding). HotSpot的对 ...
- 【面试突击】-Redis常见面试题(二)
1.什么是Redis?简述它的优缺点? Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到 ...
- Django:实现读写分离
库的配置 1.读写分离 settings配置 #settings.py 配置库信息,生成2个库 DATABASES = { 'default': { 'ENGINE': 'django.db.back ...