首页 > 其他分享 >P8029 [COCI2021-2022#3] Akcija 题解

P8029 [COCI2021-2022#3] Akcija 题解

时间:2023-09-10 14:35:13浏览次数:45  
标签:Akcija P8029 int 题解 rhs cnt State lhs 物品

:这篇题解中涉及到的所有概念均会在其第一次出现时用 斜体 标出,有些概念给出了定义,而有些概念的含义请自行意会。

定义 状态 为选了的物品数 \(a\) 与相应总价格 \(b\) 的二元组 \((a,b)\)。相应地定义状态之间的 大小关系最优状态 与状态和状态的 加法运算 \((a_1,b_1)+(a_2,b_2):=(a_1+a_2,b_1+b_2)\)。

我们先来考虑 \(k=1\) 时的做法。首先我们将商品按 \(d_i\) 排序。设 \(f(i,j)\) 表示当考虑前 \(i\) 个物品,选了 \(j\) 个时,我们 从剩余物品中能获得的 最优状态。显然可以 dp 求出。(当然正常的思维路径是设 \(f(i,j)\) 表示前 \(i\) 个物品选 \(j\) 个时的最优状态,这么设的原因见下文。)转移方程为

\[f(i,j)=\begin{cases} f(i+1,j),&d_{i+1}\le j\\ \max\{f(i+1,j),f(i+1,j+1)+(1,w_{i+1})\},&d_{i+1}\ge j+1 \end{cases} \]

接下来,我们以状态 \((0,0)\) 为 搜索树 的根,进行 Fracturing Search

按 \(d_i\) 从小到大的顺序枚举每个物品 \((w_i,d_i)\)(\(1\le i\le n\))。设考虑第 \(i\) 个物品前的前 \(k\) 优的状态集合为 \(S\),考虑完第 \(i\) 个物品后的前 \(k\) 优的状态集合为 \(T\)。枚举 \((a,b)\in S\),其 后继状态 为 \((a,b)\)(不选第 \(i\) 个物品)与 \((a+1,b+w_i)\)(选第 \(i\) 个物品,前提是 \(d_i\ge a+1\)),这些后继状态构成了集合 \(T\) 的一个超集 \(T'\)。

对于 \(s=(a,b)\in T'\),搜索树上以 \(s\) 为根的子树中,最优状态为 \(s+f(i,a)\)。我们以它为关键字,取 \(T'\) 中前 \(k\) 大的元素即构成了 \(T\)。于是,我们令 \(S\gets T\),并枚举下一个物品。

我们需要枚举 \(n\) 个物品,枚举每个物品时我们以 \(\mathcal O(k)\) 的时间复杂度计算后继状态集合 \(T\),这样,我们就以 \(\mathcal O(nk)\) 的时间复杂度解决了本题。

#include <algorithm>
#include <cstdio>
using namespace std;

using ll = long long;

const int N = 2000;

struct Node { int w, d; };
struct State { int cnt; ll sum; };
inline bool operator<(const State &lhs, const State &rhs) {
  return lhs.cnt == rhs.cnt ? lhs.sum > rhs.sum : lhs.cnt < rhs.cnt;
}
inline State operator+(const State &lhs, const State &rhs) {
  return {lhs.cnt + rhs.cnt, lhs.sum + rhs.sum};
}

int n, k;
Node a[N + 10];
State f[N + 10][N + 10];
State ans[N + 10], nxt[N + 10];

int main() {
  scanf("%d%d", &n, &k);
  for (int i = 1; i <= n; i++)
    scanf("%d%d", &a[i].w, &a[i].d);
  sort(a + 1, a + n + 1, [](const Node &lhs, const Node &rhs) {
    return lhs.d < rhs.d;
  });
  for (int i = n - 1; i >= 0; i--)
    for (int j = 0; j <= i; j++) {
      f[i][j] = f[i + 1][j];
      if (a[i + 1].d > j) f[i][j] = max(f[i][j], f[i + 1][j + 1] + State({1, a[i + 1].w}));
    }
  int tota = 1;
  for (int i = 1; i <= n; i++) {
    int totn = 0;
    for (int j = 1; j <= tota; j++) {
      nxt[++totn] = {ans[j].cnt, ans[j].sum};
      if (a[i].d > ans[j].cnt) nxt[++totn] = {ans[j].cnt + 1, ans[j].sum + a[i].w};
    }
    tota = min(k, totn);
    nth_element(nxt + 1, nxt + tota + 1, nxt + totn + 1, [&](const State &lhs, const State &rhs) {
      return rhs + f[i][rhs.cnt] < lhs + f[i][lhs.cnt];
    });
    for (int j = 1; j <= tota; j++) ans[j] = nxt[j];
  }
  sort(ans + 1, ans + k + 1, [](const State &lhs, const State &rhs) { return rhs < lhs; });
  for (int i = 1; i <= k; i++)
    printf("%d %lld\n", ans[i].cnt, ans[i].sum);
  return 0;
}

标签:Akcija,P8029,int,题解,rhs,cnt,State,lhs,物品
From: https://www.cnblogs.com/registergen/p/p8029_solution.html

相关文章

  • UVA1030 题解
    思路分析猜想我们可以在题目中看出一下几个突破口:能“看穿”的位置所对应的单位立方体是一定不存在的。如果前视图的右上角的颜色\(A\)和顶视图的的右下角颜色\(B\)不同,那么对应的格子就一定不存在。在删除这个立方体后,我们还可以发现,挖去立方体的左侧和\(B\)左侧的......
  • CF431B 题解
    思路分析答题思路一道纯暴力题!因为我们发现数据最大是\(5\),而枚举全排列的时间复杂度为\(\mathcalO(n!)\),对于这种极小的数据范围是丝毫不用顾虑的,因为我们只需要执行\(120\)次。如何快速求出一个数组的全排列?我们可以使用dfs,一层一层获取这个数组的全排列。但是STL......
  • CF387B 题解
    思路分析因为最终要使得\(a,b\)相同,所以我们应该希望让相同的数字尽量相同。所以,我们需要先对\(a\)和\(b\)进行排序,这样子就可以使用双指针的方法来维护最终值了。我们定义\(l\)指针指向\(a_l\),\(r\)指针指向\(b_r\)。因为题目要求添加数字的次数最少,所以我们希望尽......
  • P9516 题解
    思路分析一道很有洛谷个性的模拟签到题。按照题意,我们只需读入\(a,b,c,d,e\),然后对其进行求和,然后依次根据洛谷咕值系统介绍进行判断即可。这样是不是太没有意思了?今天为大家带来一点干货作为福利!介绍:accumulate()函数!简略分析:这个函数可以求出一段区间内的数字之和。S......
  • P9517 题解
    思路分析我们只需要找到左边第一个大于\(0\)的位置\(l\)与右边第一个大于\(0\)的位置\(r\),输出\(r-l+1\)即可。但是很坑的一点是,如果\(∀i∈[1,n],a_i=0\),那么\(l\)和\(r\)会重合,代码会输出\(1\)!所以,我们需要定义一个\(flag\)来标记是否全部输入为\(0\)。代......
  • UVA11210 题解
    思路分析一道大模拟。一共只有\(34\)种牌,因此可以一次判断是否“听”这些牌。比如,为了判断是否“听”一万,只需要判断自己拿到这张一万后能否可以继续和牌。这样,问题就转化成了给定\(14\)张牌,判断是否可以和牌。为此,我们可以递归求解:首先将两张牌作为“将”,然后每次选\(3\)......
  • UVA1352 题解
    思路分析构造排列表立方体只有\(4\)个,暴力法是可行的。但是如果我们要暴力,首先得清楚一个立方体到底有几种不同的旋转方式。接下来,我们用“姿态”一词代替“旋转方法”。假设\(6\)个面的编号为\(1\sim6\),从中选择一个面作为“顶面”,“顶面”的对面为“底面”。然后我们在......
  • UVA11464 题解
    思路分析暴力枚举?我们可以枚举每个数字变或不变,最后判断整个矩阵是否满足条件。但是,这样做最多需要枚举\(2^{255}≈5\times10^{67}\)中情况,是一定会超时的。大眼观察注意到\(n\le15\),第一行只有不超过\(2^{15}=32768\)种可能,所以第一行的情况是可以枚举的。接下来,根据第......
  • 题解 SP4586 Texas Trip
    首先题目翻译是有问题的,求的不是矩形而是最小的正方形。Solution先考虑一下若正方形的边都只能平行于坐标轴怎么做:找到\(x,y\)方向的坐标最值,那么答案就是\(\max^2\{X_{\max}-X_{\min},Y_{\max}-Y_{\min}\}\)。接下来,若正方形可以是斜着的,我们只需把坐标轴旋转,然后同样找出......
  • 题解 P8389【[COI2021] Izvanzemaljci】
    (本题解的所有图片使用GeometryWidget进行绘制)(一)\(K=1\)情况\(K=1\)是平凡的。(二)\(K=2\)情况显然,对于平面内的两个不交正方形,存在至少一条平行于坐标轴的直线将它们划分到两侧。以直线平行于\(y\)轴为例。考虑按\(x\)轴正方向扫描线。先将点按照\(x\)坐标排序,维......