首页 > 其他分享 >AtCoder Beginner Contest 275

AtCoder Beginner Contest 275

时间:2022-10-30 01:22:16浏览次数:89  
标签:std AtCoder le frac Beginner int sum 275 物品

咕咕咕咕咕咕。

G - Infinite Knapsack

做法1 - 二分

假设第 \(i\) 个物品选了 \(x_i\) 个,\(x_i\)为非负整数,有

\[\lim_{x \to +\infin} \frac{f(x)}{x} = \frac{\sum_i c_i x_i}{\max(\sum_i a_i x_i, \sum_i b_i x_i)} \]

所有情况中的最大值即为答案。这显然还不够优秀。

\(X\) 趋近于正无穷,相当于可以把给定物品不断等比细分, \(x_i\) 也可以是非负实数。为了简化问题,把所有物品转化成价值为 \(1\) 的物品,即重量为 \(\frac{a_i}{c_i}\) ,体积为 \(\frac{b_i}{c_i}\) ,价值为 \(1\) 。
考虑通过二分求解答案,每次检查对答案是否大于等于 \(y\),即 \(\lim_{X \to +\infin} \frac{f(X)}{X} \ge y\) ,带入得

\[\frac{\sum_i x_i}{\max (\sum_i a_i x_i, \sum_i b_i x_i)} \ge y \]

令 \(z = \frac{1}{y}\),则有

\[\begin{aligned} \max (\sum_i a_i x_i, \sum_i b_i x_i) &\le z\sum_i x_i\\ \max (\sum_i (a_i - z) x_i, \sum_i (b_i - z) x_i) &\le 0 \end{aligned} \]

然后分类讨论:

  • \(a_i - z \le 0, b_i - z \le 0\):存在这类物品即可行。
  • \(a_i - z > 0, b_i - z > 0\):这类物品属于无用物品。
  • \(a_i - z < 0, b_i - z \ge 0\)
  • \(a_i - z \ge 0, b_i - z < 0\)

现在只需要考虑后两类物品,不妨将其都放缩为 \((-1, B)\) 或者 \((A, -1)\) ,然后贪心只考虑 \(A\) 最小和 \(B\) 最小的物品。现在只需要看是否能构造出 \((x, y)\) 使得 \(\max(-x + yA, xB - y) \le 0\) ,解方程得只需 \(AB \le 1\)。

实现的时候可以直接二分 \(z\),最后再求个倒数得到 \(y\)。

AC代码
// Problem: G - Infinite Knapsack
// Contest: AtCoder - AtCoder Beginner Contest 275
// URL: https://atcoder.jp/contests/abc275/tasks/abc275_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Author: Backlight
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO                       \
  std::ios::sync_with_stdio(false); \
  std::cin.tie(0);                  \
  std::cout.tie(0);

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#define ASSERT(x) ;
#define serialize() std::string("")
#endif

using i64 = int64_t;
using u64 = uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;

void Initialize();
void SolveCase(int Case);

int main(int argc, char* argv[]) {
  CPPIO;

  Initialize();

  int T = 1;
  // std::cin >> T;
  for (int t = 1; t <= T; ++t)
    SolveCase(t);
  return 0;
}

void Initialize() {}

void SolveCase(int Case) {
  int n;
  std::cin >> n;

  std::vector<std::array<double, 2>> p(n);
  for (int i = 0; i < n; ++i) {
    int a, b, c;
    std::cin >> a >> b >> c;
    p[i] = {1.0 * a / c, 1.0 * b / c};
  }

  auto check = [&](double x) {
    double A = 1e18, B = 1e18;
    for (int i = 0; i < n; ++i) {
      double a = p[i][0] - x;
      double b = p[i][1] - x;
      if (a <= 0 && b <= 0)
        return true;

      if (a < 0)
        B = std::min(B, b / (-a));
      if (b < 0)
        A = std::min(A, a / (-b));
    }

    if (A == 1e18 || B == 1e18)
      return false;
    return A * B <= 1;
  };

  const double eps = 1e-8;
  double l = 0, r = 1e18, mid;
  while (r - l >= eps) {
    mid = (l + r) / 2;

    if (check(mid))
      r = mid;
    else
      l = mid;
  }

  std::cout << std::fixed << std::setprecision(12) << 1 / l << "\n";
}

做法2 - 凸包

同样的先把物品转化成价值为 \(1\) 的物品。然后,对于两个物品 \((a_i, b_i)\) 和 \((a_j, b_j)\) ,如果 \(a_i < a_j\) 且 \(b_i < b_j\) ,那么选 \((a_i, b_i)\) 肯定不如 \((a_j, b_j)\)。把 \((a_i, b_i)\) 看成二位平面上的点,则如果一个点的左下角有点,则这个点就不需要考虑。

求出点集的凸包,则只需要考虑下凸包上的点。

然后,由于 \(X\) 趋近于正无穷,物品可以无限细分,所以可以把下凸包上的线段也看成点,相当于用线段两个端点对应物品合成一个新的物品。然后根据前面的观察,不需要考虑 \(3\) 个及以上物品的合成,也不需要考虑不相邻的物品的合成。

然后就是模拟了。

代码咕咕咕。

Ex - Monster

To be solved。

标签:std,AtCoder,le,frac,Beginner,int,sum,275,物品
From: https://www.cnblogs.com/zengzk/p/16840354.html

相关文章

  • AtCoder Regular Contest 060
    F题有循环节,一看就有KMP,比较难,太晚了,早上起来再补。C-TakandCards\(n\)个整数\(a_1\sima_n\),问有多少种选数方案,使得选出来的数平均值为\(A\)。\(1\len,a_i......
  • AtCoder Regular Contest 059
    EducationalDPRound(确信C-BeTogether给定\(n\)个数\(a_{1}\sima_n\),你至多可以对每个\(a_i\)操作一次,以\((a_i-y)^2\)的代价令\(a_i\getsy\),求\(a\)全......
  • Atcoder Grand Contest 003(A~F)
    赛时打了80分钟,后来因为要处理一些私事就没再打,过掉了ABC,推了DE没推出来,不能算很差,但也不算很好。总结一下吧。赛时A一眼题,统计四个方向是否出现过,如果相对的两......
  • AtCoder Beginner Contest 247 E - Max Min
    题目描述简要描述:给定一个长度为\(N\)的数组,求数组的子数组满足最大值为\(X\)且最小值为\(Y\)的子区间的个数。做法1.ST表+二分时间复杂度:\(O(n\logn)\)......
  • AtCoder Beginner Contest 266 Ex Snuke Panic (2D)
    AtCoder传送门洛谷传送门考虑dp,\(f_i\)设在\(t_i\)时刻到达第\(i\)个点,能获得的最大收益。转移:\(f_i=f_j+a_i\),其中\(j\)能转移到\(i\)的充要条件有:\(......
  • AtCoder Beginner Contest 201 题解
    vp情况:过了A到E,F没时间也不会。vp总结:ABC表现可以。D慢了一点,写之前大概考虑清楚每个变量或函数的意义,结构明晰才能更快的写出代码。E花的时间太长,原因......
  • D - Div Game -- ATCODER
    D-DivGamehttps://atcoder.jp/contests/abc169/tasks/abc169_d参考:https://blog.csdn.net/justidle/article/details/106474626 思路计算n中所有质数的幂,No......
  • Atcoder Grand Contest 002(A~F)
    这场打的还算舒服(虽然DE好像很久以前做过谔谔),VP赛时切掉了A~D,不过E依旧没写出来,还是太逊啦!赛时A简单分类讨论,求\(a\)到\(b\)之间数的乘积,第一眼看成了和,痛......
  • D - LRUD Instructions -- ATCODER
    D-LRUDInstructionshttps://atcoder.jp/contests/abc273/tasks/abc273_d 分析横坐标和纵坐标很大,不能采用二维数组形式,否则内存干爆,目标对象移动,按照指令进行移动......
  • AtCoder Beginners Contest 274 Editoral
    AtCoderBeginnersContest274Editoral目录AtCoderBeginnersContest274EditoralTaskA-BattingAverageProblemStatementSampleData题面翻译SourceCode解析Tas......