Codeforces 611 E New Year and Three Musketeers

传送门: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;
}
内容概要:本文详细介绍了基于Matlab实现的“梯级水光互补系统最大化可消纳电量期望短期优化调度模型”,属于电力系统领域高水平科研成果的复现(EI级别)。该模型聚焦于梯级水电站与光伏发电系统的协同优化调度,通过构建短期优化调度框架,旨在提升可再生能源的电量消纳能力并最大化系统综合效益。研究采用先进的数学优化方法对水光资源进行联合调度,充分考虑了光伏出力的不确定性、水资源约束、系统运行边界条件及电力平衡要求,实现了在多重约束下的电量期望最大化目标。模型不仅具备严谨的理论基础,还具有良好的工程应用前景,适用于新能源高比例渗透背景下电力系统的优化调度研究与实践。; 适合人群:具备电力系统分析、可再生能源利用或优化建模背景的研究生、科研人员及工程技术人员,特别适合致力于复现高水平学术论文(EI/顶刊)研究成果的学习者与开发者。; 使用场景及目标:① 学习并掌握梯级水电与光伏系统协同调度的建模思路与关键技术;② 熟悉基于Matlab的混合整数线性规划(MILP)或其他非线性优化方法在能源系统中的实际应用;③ 提升在新能源消纳、短期调度优化等方向的科研建模能力与代码实现水平,支持二次开发与创新研究。; 阅读建议:建议结合Matlab代码与优化理论同步研读,重点理解目标函数的设计逻辑、各类物理与运行约束的数学表达以及求解器的调用流程,推荐使用YALMIP等建模工具辅助实现,以提高模型构建效率与可读性,便于深入理解与后续拓展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值