CF277D Google Code Jam

CF277D Google Code Jam

\(n\) 道题目,每道题分为小题目和大题目,只有做完了小题目才能做大题目,提交结果会在比赛结束后得知。其中,做第 \(i\) 个小题目需要 \(ScoreSmall_i\) 分钟,可以获得得分 \(TimeSmall_i\) ;做第 \(i\) 个大题目需要 \(ScoreLarge_i\) 分钟,可以获得得分 \(TimeLarge_i\) 。每个小题目可以一遍过,第 \(i\) 个大题目有 \(ProbFail_i\) 的几率错误,总罚时是 最后一次正确提交的时间。现在你有 \(t\) 分钟,求在这 \(t\) 分钟内你最多期望能够获得多少分,并且在满足得分最多的情况下使得罚时最小。

\(n\leq1000;t,\ TimeSmall_i,\ TimeLarge_i\in[1,\ 1560];\ ScoreSmall_i,\ ScoreLarge_i\in[1,\ 10^9];\ 0\leq ProbFail_i\leq 1\)

dp,贪心,概率


背包可以解决最高得分,那么现在要找到一种最优的顺序使得罚时最低。

可以发现 \(Small\) 对罚时没有特殊影响,可以直接计算。假设需要解决两道题 \(i,\ j\)\(Large\) ,令 \(t_i=TimeLarge_i,\ p_i=ProbFail_i\),若 \(i\) 排在 \(j\) 之前,罚时为 \((1-p_j)(t_i+t_j)+t_i(1-p_i)p_j\)

化式子得,若 \(i\) 排在 \(j\) 之前的得分大于 \(j\) 排在 \(i\) 之前当且仅当 \(t_i\times p_i/(1-p_i)>t_j\times p_j/(1-p_j)\)

按照这个规则排序即可。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long double db;
const db eps = 1e-15;
const int maxn = 2010;
int n, m;
db dp[maxn], val[maxn];

struct node {
  int v1, v2, t1, t2; db p;
  
  inline bool operator < (const node &o) const {
    return t2 * p / (1 - p) < o.t2 * o.p / (1 - o.p);
  }
} a[maxn];

int main() {
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; i++) {
    double f;
    scanf("%d %d %d %d %lf", &a[i].v1, &a[i].v2, &a[i].t1, &a[i].t2, &f);
    a[i].p = f;
  }
  sort(a + 1, a + n + 1);
  for (int i = 1; i <= m; i++) {
    dp[i] = -1e18, val[i] = 1e18;
  }
  for (int i = 1; i <= n; i++) {
    db p = a[i].p, tmp1, tmp2;
    int v1 = a[i].v1, v2 = a[i].v2;
    int t1 = a[i].t1, t2 = a[i].t2;
    for (int j = m; j >= t1; j--) {
      tmp1 = dp[j - t1] + v1, tmp2 = val[j - t1] + t1;
      if (dp[j] < tmp1 || (fabs(dp[j] - tmp1) < eps && val[j] > tmp2)) {
        dp[j] = tmp1, val[j] = tmp2;
      }
      if (j < t1 + t2) continue;
      tmp2 = dp[j - t1 - t2] + v1 + (1 - p) * v2;
      tmp1 = t1 + (1 - p) * (j - t1) + p * val[j - t1 - t2];
      if (dp[j] < tmp2 || (fabs(dp[j] - tmp2) < eps && val[j] > tmp1)) {
        dp[j] = tmp2, val[j] = tmp1;
      }
    }
  }
  int pos = 0;
  for (int i = 1; i <= m; i++) {
    if (dp[pos] < dp[i] || (fabs(dp[pos] - dp[i]) < eps && val[i] < val[pos])) {
      pos = i;
    }
  }
  printf("%.10lf %.10lf", (double) dp[pos], (double) val[pos]);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Juanzhang/p/11334597.html