CodeForces 1019A
A. 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 — \(n\) and \(m\) 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 \(i\)-th voter \(c_i\) 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 \(n\) and \(m\) (\(1 \le n, m \le 3000\)) — the number of voters and the number of parties respectively.
Each of the following \(n\) lines contains two integers \(p_i\) and \(c_i\) (\(1 \le p_i \le m\), \(1 \le c_i \le 10^9\)) — 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 \(1\).
Output
Print a single number — the minimum number of bytecoins needed for The United Party of Berland to win the elections.
Examples
input
1 2
1 100
output
0
input
5 5
2 100
3 200
4 300
5 400
5 900
output
500
input
5 5
2 100
3 200
4 300
5 800
5 900
output
600
这题有两种解法
第一种解法:贪心暴搜
根据题意,一共有N票,M个候选人
数据范围是[1,3000],比较小,可以暴搜
先要把每一票记录下来,按花费从小到大排序
我们假设最终每个候选人不超过k票,而我们的目标(1号候选人)至少要有k票
把达成这个目标的成本记录下来,从1到N遍历求最小值就好了(我尝试过N/2也能过,差异不大)
那么这个计算的过程是这样的:
按花钱从小到大的顺序遍历,
假如说这票是1号的,就跳过
假如说这个投票人投票的对象的票数 < k,暂且跳过
假如说这个投票人投票的对象的票数 > k,那就把这票抢过来
如果完成上面三个过程之后,1号的票数还是 < k,那就按照花费从小到大的顺序,还没抢过来的就抢过来,直到 ≥ k 为止。
第二种解法:三分
在用三分解决这道题目之前,首先你要了解什么是三分(不知道就点这里)
剩下的就很简单了,这个图像可以近似看成一个方向向下的凹函数,套上板子就好了
我的代码
#include <bits/stdc++.h>
#define int long long
struct node{
int peo,cost;
bool operator < (const node &a){
return this->cost < a.cost;
}
};
int n,m;
const int N = 3010;
node inp[N];
std::vector<int> num(N);
int check(int max_c)
{
int ans = 0;
bool book[N];
std::vector<int> p(num);
for(int i = 0 ; i < n ; i ++)
{
if(inp[i].peo == 1) book[i] = true;
else if(p[inp[i].peo] < max_c) book[i] = false;
else
{
book[i] = true;
p[1] ++;
p[inp[i].peo] --;
ans += inp[i].cost;
}
}
for(int i = 0 ; i < n && p[1] < max_c; i ++)
{
if(book[i] == true) continue;
else
{
p[1]++;
ans += inp[i].cost;
}
}
return ans;
}
signed main()
{
std::cin >> n >> m;
for(int i = 0 ; i < n ; i ++)
{
std::cin >> inp[i].peo >> inp[i].cost;
num[inp[i].peo]++;
}
std::sort(inp,inp + n);
//贪心暴搜代码
/*
int ans = check(1);
for(int i = 2 ; i <= N/2 + N%2 ; i ++)
{
ans = std::min(ans,check(i));
}
std::cout << ans;
*/
//三分代码
int l=0,r=n-1;
while(l < r-1)
{
int mid = l + r >> 1;
int mmid = r + mid >> 1;
if(check(mid) > check(mmid))
l = mid;
else
r = mmid;
}
std::cout << std::min(check(l),check(r));
return 0;
}
PS:
思路参考:(大佬链接指路)