题意
给竞选队伍投票,每个选民经过贿赂之后可以将票交给你
给出当前的投票情况和价格
求第一个队伍最少要花多少钱才能保证自己赢(票数超过其他所有人)
思路
因为可以从对方抢票,双方一减一增,不好确定最终到底多少票就能赢
枚举其他人的最多票数,求出能保证自己一定超过这个票数下的最小花费
如果当前 i 比最多票的队伍们小,则一定要从票多的人那里抢
剩下的用前述最少的票来补齐就可以了
代码
(感觉自己对枚举一直不怎么敏感…
知道思路之后自己也做不出来,细节差,开了双层的优先队列..时间炸了
学一波vector(orz
#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const ll INF = 0x7f7f7f7f7f7f7f7f;
const int maxn = 10000 + 10;
int n, m; //投票人数,竞争队伍数
//二维的向量
vector<vector<int>> num;
void solve () {
ll sol = INF;
//枚举i,表示所有其他队伍都不会超过i票
for ( int i = 1; i <= n; ++i ) {
ll ans = 0;
int ct = num[ 1 ].size ();//已经有了的票数
//记录各个队伍哪些票已经被取走了,初始化大小为1到m个
vector<int> indx ( m + 1, 0 );
// 取出比当前预期票数多的队伍的票
for ( int j = 2; j <= m; ++j ) {
//保证票多的队伍剩余的票数 < i个
while ( (int)num[ j ].size () - indx[ j ] >= i ) {
ans += num[ j ][ indx[ j ] ];
indx[ j ]++;
ct++;
}
}
if ( ct >= i )
sol = min ( sol, ans );
else {
//将剩下的放到一起,依旧用了vector
vector<int> rest;
for ( int j = 2; j <= m; ++j ) {
for ( int k = indx[ j ]; k < (int)num[ j ].size (); ++k )
rest.push_back ( num[ j ][ k ] );
}
sort ( rest.begin (), rest.end () );
int k = 0;
//不够数量,则从最便宜的票里选知道数目足够
while ( ct < i ) {
ans += rest[ k++ ];
ct++;
}
sol = min ( sol, ans );
}
}
printf ( "%lld\n", sol );
}
int main () {
#ifdef LOCAL
freopen ( "in", "r", stdin );
// freopen("out","w",stdout);
#endif
while ( ~scanf ( "%d%d", &n, &m ) ) {
num.clear ();
num.resize ( m + 1 );
for ( int i = 0; i < n; ++i ) {
int id, cst;
scanf ( "%d%d", &id, &cst );
num[ id ].push_back ( cst );
}
for ( int i = 2; i <= m; ++i )
sort ( num[ i ].begin (), num[ i ].end () );
solve ();
}
return 0;
}