题目描述:

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. nginx http和https共存

    server { listen 80 default backlog=2048; listen 443 ssl; server_name linuxyan.com; root /var/www/htm ...

  2. url、href、src

    一.URL的概念 统一资源定位符(或称统一资源定位器/定位地址.URL地址等,英语:Uniform Resource Locator,常缩写为URL),有时也被俗称为网页地址(网址).如同在网络上的门 ...

  3. 【SSH进阶之路】Hibernate系列——总结篇(九)

    这篇博文是Hibernate系列的最后一篇,既然是最后一篇,我们就应该进行一下从头到尾,整体上的总结,将这个系列的内容融会贯通. 概念 Hibernate是一个对象关系映射框架,当然从分层的角度看,我 ...

  4. leetcode刷题系列(一) 26题 删除排序数组中的重复项

    题干 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示 ...

  5. Django框架深入了解_01(Django请求生命周期、开发模式、cbv源码分析、restful规范、跨域、drf的安装及源码初识)

    一.Django请求生命周期: 前端发出请求到后端,通过Django处理.响应返回给前端相关结果的过程 先进入实现了wsgi协议的web服务器--->进入django中间件--->路由f分 ...

  6. git最基本的操作: add commit push 哈哈

    Git add     //添加到本地暂存区 Git commit -m”xxxxx”   //添加到本地分支 Git push      //添加到远端分支

  7. DFS BFS 学习总结

    DFS 深度优先搜索 基本思路: if(true) 返回 典型例题: 1.马走日(非常典型) #include<iostream> #include<cstring> usin ...

  8. LeetCode 1259. Handshakes That Don't Cross - Java - DP

    题目链接:https://leetcode-cn.com/problems/handshakes-that-dont-cross/ You are given an even number of pe ...

  9. DS AVL树详解

    先说说二叉搜索树: 是有序的二叉树,根值>左节点值,右节点值>根值. 如果要查找某个值,二叉搜索树和二分查找一样,每进行一次值比较,就会减少一半的遍历区间. 但是,如果树插入的值一直递增/ ...

  10. Python与MogoDB交互

    睡了大半天,终于有时间整理下拖欠的MongoDB的封装啦. 首先我们先进行下数据库的连接: conn = MongoClient('localhost',27017) # 建立连接 result = ...