keidaroo’s diary

底辺系競プロer

SRM 605 div1 easy AlienAndHamburgers

ひえ〜〜めっちゃ失敗した

概要

とある宇宙人は地球を滅ぼす前にハンバーガーを食べたいと思った。
N 個のハンバーガーがある。各ハンバーガーは二つの属性 type と taste をもち、それぞれ整数値で表される。
これらのハンバーガーのうち、いくつかを選んで食べる。(食べた種類の数 × taste の合計)が最大となるように食べたときの、この値を求めよ。

失敗談

DPをしようとおもった

DP案1

dp[何個目についてみるか][何種類とったか] = 合計のtaste

今思うと自分頭悪すぎ..

これだと最終的に何種類とったかわからない、そうすると2種類とって100っていうのと、3種類とって99だと2*100<3*99なのに100>99なので2種類しか取っていない100が採用される。
「何種類とったか」が関係するのではなくて、「最終的に何種類とったか」が関係する、、ので、、

DP案2

「何種類とったか」が関係するのではなくて、「最終的に何種類とったか」が関係する、、ので、、

  • > せやな、dp[何個目についてみるか][何種類とったか] = 合計のtaste * 合計のtypesにしたろ

今思うと自分頭わるすぎ,,,(n回目)
なぜかというと[何個目についてみているか]以降のtasteの最大値じゃあ、何種類とったほうがいいかというのは判断できない

例)
i個目までに
1000のtaste
i個目以降では
2種類とって-100
3種類とって-200

の時に-100*2>-200*3だが、i個目までの合計を考えると
990*2<980*3

になる、、

教訓: i個目以前の結果が関連づいてくるDPは書いてはいけない(書くとしたら必ずdpの添字に追加する必要がある)

最終的に

i種類とるとき、tasteが最大値を取るときに最大になる!wと気づき、4時間かけてようやくソートして貪欲した、、頭悪い、、

見るとSugarDragon5君などが余裕でACしていて人生つらい気持ちになった
sugardragon5.hatenadiary.com

#include <bits/stdc++.h>
#define pb push_back
#define REP(i, n) for (signed long long i = 0; i < (n); i++)
#define MOD 998244353
#define INF 93193111451418101
#define bitcnt(a) (ll) __builtin_popcount((a))
#define lb(a, b) lower_bound((a).begin(), (a).end(), (b))
#define ub(a, b) upper_bound((a).begin(), (a).end(), (b))
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;

bool positive[101];

ll maxTaste[103], tasteSum[103];
P dp[51][51];

set<ll> vis;

vector<ll> num;

class AlienAndHamburgers {

public:
  int getNumber(vector<int> type, vector<int> taste) {
    REP(i, 101) {
      maxTaste[i] = -INF;
    }
    REP(i, (signed)type.size()) {
      vis.insert(type[i]);

      if (taste[i] > 0) {
        positive[type[i]] = true;
        tasteSum[type[i]] += taste[i];
      }
      maxTaste[type[i]] = max(maxTaste[type[i]], (ll)taste[i]);
    }

    for (auto &a : vis) {
      if (positive[a]) {
        num.pb(tasteSum[a]);
      } else {
        num.pb(maxTaste[a]);
      }
    }
    sort(num.begin(), num.end(), greater<ll>());
    ll ret = 0, im = 0;
    REP(i, (signed)num.size()) {
      im += num[i];
      ret = max(ret, im * (i + 1));
    }
    return ret;
  }
};