题目描述:

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(贪心枚举三分)的更多相关文章

  1. CodeForces - 1020C C - Elections(贪心+枚举)

    题目: 党派竞争投票 有n个人,m个党派,这n个人每个人有一个想要投的党派的编号Pi,如果想要这个人改变他的想法,那么就需要花费Ci元钱. 现在你是编号为1的党派,如果你想要赢(你的票数严格大于其他党 ...

  2. 【BZOJ3874】[AHOI&JSOI2014]宅男计划(贪心,三分)

    [BZOJ3874][AHOI&JSOI2014]宅男计划(贪心,三分) 题面 BZOJ 洛谷 题解 大力猜想一最长的天数和购买外卖的总次数是单峰的.感性理解一下就是买\(0\)次是\(0\) ...

  3. Codeforces 458C - Elections

    458C - Elections 思路: 三分凹形函数极小值域 代码: #include<bits/stdc++.h> using namespace std; #define ll lo ...

  4. codeforces 578c - weekness and poorness - 三分

    2017-08-27 17:24:07 writer:pprp 题意简述: • Codeforces 578C Weakness and poorness• 给定一个序列A• 一个区间的poornes ...

  5. CodeForces - 158B.Taxi (贪心)

    CodeForces - 158B.Taxi (贪心) 题意分析 首先对1234的个数分别统计,4人组的直接加上即可.然后让1和3成对处理,只有2种情况,第一种是1多,就让剩下的1和2组队处理,另外一 ...

  6. POJ 1018 Communication System 贪心+枚举

    看题传送门:http://poj.org/problem?id=1018 题目大意: 某公司要建立一套通信系统,该通信系统需要n种设备,而每种设备分别可以有m个厂家提供生产,而每个厂家生产的同种设备都 ...

  7. 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 ...

  8. codeforces 613B B. Skills(枚举+二分+贪心)

    题目链接: B. Skills time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  9. 【codeforces 761C】Dasha and Password(贪心+枚举做法)

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

随机推荐

  1. AIX日志相关的命令

    常用的命令有: 1.列出简短的出错信息 errpt | more 2.列出所有硬件出错信息 errpt -d H 3.列出所有软件错误信息 errpt -d S 4.列出详细的出错信息 errpt – ...

  2. 【Spring Boot学习之四】Spring Boot事务管理

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 一.springboot整合事务事务分类:编程事务.声明事务(XML.注解),推荐使用注解方式,springboot默 ...

  3. Ajax跨域请求附带Cookie/Ajax跨域请求附带身份凭证

    一.跨域请求中默认不带cookie等验证凭证 尤其对于post请求. 对于ajax请求,其中post,get都可以正常访问. withCredentials: false, // 允许携带cookie ...

  4. mysql报错 常见 1045 10061

    报错1045: 远程没有设置用户远程访问的权限 解决方案: 进行授权(红色是你的密码) 如果想root用户使用password从任何主机连接到mysql服务器的话. GRANT ALL PRIVILE ...

  5. php 按照字典序排序 微信卡券签名算法用到

    代码 <?php $data=array("api_ticket"=>"IpK_1T69hDhZkLQTlwsAXzJqxGE_7RuU_tjnx8rWC9f ...

  6. Delphi 开发微信公众平台 (三)- 获取微信服务器IP地址

    如果公众号基于安全等考虑,需要获知微信服务器的IP地址列表,以便进行相关限制,可以通过该接口获得微信服务器IP地址列表或者IP网段信息. 接口调用请求说明 http 请求方式: GET https:/ ...

  7. Python使用队列实现Josephus问题

    Josephus问题,在这个古老的问题中,N个深陷绝境的人一致同意通过以下方式减少生存的人数.他们围坐一圈(位置记为0~N-1)并从第一个人报数,报到M的人会被杀死, 知道最后一个人留下来.传说中Jo ...

  8. CSS3弹性盒布局方式

    一.CSS3弹性盒子 弹性盒子是CSS3的一种新布局模式. CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的 ...

  9. LOJ2461 完美的队列 分块

    传送门 如果对于每一个操作\(i\)找到这个操作中所有的数都被pop掉的时间\(ed_i\),那么剩下就直接差分覆盖一下就可以了. 那么考虑如何求出\(ed_i\).发现似乎并没有什么数据结构能够维护 ...

  10. 全栈项目|小书架|服务器端-NodeJS+Koa2 实现搜索功能

    搜索功能会包含:热搜.搜索列表. 热搜功能在电商的搜索中经常看到,热搜数据的来源有两种 用户真实的搜索数据,根据算法进行排序 人为推送的数据 想想微博热搜是可以买的就知道热搜功能多么重要了. 我采用第 ...