传送门:http://codeforces.com/problemset/problem/611/E
首先贴上一份我orz的代码
非常暴力的写法,从变量名的命名,再到multiset的运用,和完美地每一步英文注释,还有三维比较(3层meke_pair的方法)
其实这个方法主要的核心就是比较优先级的定义
#include <bits/stdc++.h>
#define LL long long
#define ABS(a) (((a) > 0) ? (a) : (-(a)))
#define FOR(i,n) for(int i=0;i<(n);++i)
#define FORIT(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define all(o) (o).begin(), (o).end()
#define pb push_back
#define mp make_pair
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define MOD 1000000007
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> pii;
template<typename T> ostream& operator<<(ostream& s, vector<T>& v)
{ s << '{'; for (int i = 0 ; i < v.size(); ++i) s << (i ? "," : "") << v[i]; return s << '}'; }
template<typename S, typename T> ostream& operator<<(ostream &s, pair<S,T>& p)
{ return s << "(" << p.first << "," << p.second << ")"; }
multiset<int> enemies;
void swap(int &a, int &b){
int t = a;
a = b;
b = t;
}
int sumv(vector<int> &v){
int x = 0;
FOR(i,v.size()) x += v[i];
return x;
}
int vmax(vector<int> &v){
int x = 0;
FOR(i,v.size()) x = max(x,v[i]);
return x;
}
int main(){
int N;cin>>N;
int A,B,C;cin>>A>>B>>C;
FOR(i,N){
int t;cin>>t;
enemies.insert(t);
}
if(A>B) swap(A,B);
if(A>C) swap(A,C);
if(B>C) swap(B,C);
// max of any 2 musketeers
int max2 = B+C;
int max1 = C;
// Heuristic: always kill the biggest enemy, but then try to kill as many as possible
int iters = 0;
bool impossible = false;
while(enemies.size() > 0){
int best_powkill = 0;
int best_numkill = 0;
int best_sumkill = 0;
vi best_kill;
FOR(i1,3){
FOR(i2,3){
FOR(i3,3){
vi team[3];
team[i1].pb(A);
team[i2].pb(B);
team[i3].pb(C);
if(sumv(team[0]) < sumv(team[1])) continue;
if(sumv(team[1]) < sumv(team[2])) continue;
//cout << team[0] << " " << team[1] << " " << team[2] << endl;
vi kill;
FOR(i,3){
int power = sumv(team[i]);
// kill biggest thing with our power
multiset<int>::iterator it = enemies.upper_bound(power);
if(it == enemies.begin()){
}
else{
it--;
// kill it
kill.pb(*it);
enemies.erase(it);
}
}
// evaluate
int powkill = vmax(kill);
int numkill = kill.size();
int sumkill = sumv(kill);
// first powkill, then numkill, then sumkill
if(mp(mp(powkill, numkill), sumkill) > mp(mp(best_powkill, best_numkill), best_sumkill)){
best_powkill = powkill;
best_numkill = numkill;
best_sumkill = sumkill;
best_kill = kill;
}
// restore killed
FOR(i,kill.size()){
enemies.insert(kill[i]);
}
}
}
}
// actually kill them
//cout << best_kill << endl;
FOR(i,best_kill.size()){
enemies.erase(enemies.lower_bound(best_kill[i]));
}
iters++;
if(best_kill.size() == 0){
impossible = true;
break;
}
}
if(impossible){
cout << -1 << endl;
}
else{
cout << iters << endl;
}
}
再贴上此题目的标解:
首先令a<=b<=c
然后根据大小关系可以依次使用a+b+c,b+c,a+c以这几种组合的方式每次杀掉一定的怪物,然后就是讨论环节了:
因为a+b和c的大小关系并不确定,所以每次只能使用a+b,c或者是a,b,c
注意到用a+b,c的方案可以在O(1)的时间内计算得出
具体可以参见题解:
http://codeforces.com/blog/entry/22441
// Musketeers
// AC, O(n log(n))
// by Errichto
#include<bits/stdc++.h>
using namespace std;
const int nax = 1e6 + 5;
const int inf = 1e9 + 5;
int m[3];
multiset<int> enemies;
void greedy(int atLeast, int extra, int & ans) {
while(!enemies.empty()) {
auto it = enemies.end();
--it;
if(*it < atLeast) break;
enemies.erase(it);
++ans;
it = enemies.lower_bound(extra);
if(it != enemies.begin()) {
--it;
enemies.erase(it);
}
}
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < 3; ++i) scanf("%d", &m[i]);
sort(m, m + 3);
for(int i = 0; i < n; ++i) {
int x;
scanf("%d", &x);
--x;
enemies.insert(x);
}
int all = m[0] + min(inf, m[1] + m[2]);
auto it = enemies.end();
--it;
if(*it >= all) {
puts("-1");
return 0;
}
int ans = 0;
greedy(m[1] + m[2], 0, ans);
greedy(m[0] + m[2], m[0], ans);
greedy(max(m[0]+m[1], m[2]), m[1], ans);
int one = 0, two = 0;
for(int x : enemies) {
if(x < m[0] + m[1]) ++one;
if(x < m[2]) ++two;
}
int best = inf;
for(int rep = 0; rep < n + 5; ++rep) {
if(max(one, two) == (int) enemies.size()) {
if(2 * min(one, two) >= (int) enemies.size()) best = min(best, rep + ((int) enemies.size() + 1) / 2);
else best = min(best, rep + (int) enemies.size() - min(one, two));
}
for(int i = 0; i < 3; ++i) {
auto it = enemies.lower_bound(m[i]);
if(it != enemies.begin()) {
--it;
if(*it < m[0] + m[1]) --one;
if(*it < m[2]) --two;
enemies.erase(it);
}
}
}
printf("%d\n", ans + best);
return 0;
}

1178

被折叠的 条评论
为什么被折叠?



