首页 > 其他分享 >LOJ#4149. 「JOISC 2024 Day1」滑雪 2

LOJ#4149. 「JOISC 2024 Day1」滑雪 2

时间:2024-05-26 10:55:42浏览次数:40  
标签:增高 4149 LOJ hs ll 高度 Day1 int lhs

首先,不存在 \(H_i < H_j\) 时增高 \(H_i\) 至 \(H_j + 1\) 后连 \(i \to j\) 更优,因为增高后原来能连 \(i\) 的点现在不一定能连 \(i\) 了,原来能连 \(j\) 的点还是能连 \(j\),此时的方案集必然是原方案集的子集,答案一定不会更优,又因为你付出了增高的费用,所以这样一定劣。

那么我们就只会对存在 \(j \ne i\),满足 \(H_j = H_i, C_j \le C_i\) 的点 \(i\) 增高。

所以可以把高度离散化到 \(O(n)\) 个,留 \(H_i, H_i + 1\)​ 即可。

考虑 DP。

增高是不好判断的,考虑通过状态上的限制来完成增高。

我们以高度为横轴,相同高度按 \(C_i\) 填点。

样例就可以画成这样:

最后出答案的图长这样:

记图上第 \(i\) 个高度下的最大纵坐标为 \(y_i\),则对于任一高度 \(j\),其所能容纳的最多无需付费的点的数量就是 \(\max\limits_{k=0}^{j-1} y_k\),记这个数量为 \(t_j\),显然 \(t_j\) 不降。

我们考虑限制 \(t_j\) 来使得一些点被迫增高。

设 \(f(i, j, k)\) 表示填完前 \(i - 1\) 个高度,现在在填第 \(i\) 个高度,此前所有高度的 \(y\) 的最大值为 \(j\),前 \(i - 1\) 个高度给当前高度剩了 \(k\) 个点的最小花费。

初值:\(f(i, j, k) = +\infin, f(0, 1, 0) = 0\);答案:\(\min\limits_{j=1}^n f(m, j, 0)\),其中 \(m\) 为离散化后的高度数。

我们可以通过付出 \(mn\) 的代价来增加一个连接装置,使 \(t_i\) 增加 \(1\),至于哪个点增加,贪心选最小的即可。记 \(mn\) 为高度小于第 \(i\) 个高度的点中 \(C_i\) 的最小值,则有:

\[f(i, j, k) + mn \to f(i, j + 1, k) \]

然后就是填点:

\[f(i, j, k) + F(j, h_{i+1} - h_i, k + cnt_i) \times K \to f(i + 1, j, \max\{k + cnt_i - (h_{i+1} - h_i)j, 0\}) \]

其中 \(F(n, m, k)\) 表示将 \(k\) 个点放到最大点数为 \(m\) 的个 \(n\) 个高度中的增高操作次数,显然可以 \(\mathcal O(1)\) 计算。

\(f(i, j, k)\) 可以滚动掉 \(i\) 一维,但没必要。

时间复杂度 \(\mathcal O(n^3)\)。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 310;
constexpr ll INF = 0x3f3f3f3f3f3f3f3f;

int n, h[N], c[N], cnt[N << 1], mnc[N << 1];
ll K, f[N << 1][N][N];

vector<int> hs;

inline ll F(int n, int m, int k) {
	n = min(n, k / m);
	return n * (n - 1) / 2 * m + n * (k - n * m);
}

inline void chkmin(int &lhs, int rhs) {lhs = min(lhs, rhs);}
inline void chkmin(ll &lhs, ll rhs) {lhs = min(lhs, rhs);}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> K;
	for (int i = 1; i <= n; i++) cin >> h[i] >> c[i], hs.emplace_back(h[i]), hs.emplace_back(h[i] + 1);
	sort(hs.begin(), hs.end()); hs.erase(unique(hs.begin(), hs.end()), hs.end());
	memset(mnc, 0x3f, sizeof(mnc));
	for (int i = 1; i <= n; i++) {
		h[i] = lower_bound(hs.begin(), hs.end(), h[i]) - hs.begin();
		cnt[h[i]]++, chkmin(mnc[h[i]], c[i]);
	}
	memset(f, 0x3f, sizeof(f)), f[0][1][0] = 0;
	int m = hs.size(), mn = 2e9;
	for (int i = 0; i < m; i++) {
		int wid = i + 1 < m ? min(n, hs[i + 1] - hs[i]) : n;
		for (int j = 1; j <= n; j++) {
			for (int k = 0; k <= n; k++) if (f[i][j][k] < INF) {
				chkmin(f[i][j + 1][k], f[i][j][k] + mn);
				chkmin(f[i + 1][j][max(k + cnt[i] - wid * j, 0)], f[i][j][k] + F(wid, j, k + cnt[i]) * K);
			}
		}
		mn = min(mn, mnc[i]);
	}
	ll ans = INF;
	for (int j = 1; j <= n; j++) ans = min(ans, f[m][j][0]);
	cout << ans;
	return 0;
}

标签:增高,4149,LOJ,hs,ll,高度,Day1,int,lhs
From: https://www.cnblogs.com/chy12321/p/18213414

相关文章

  • 今日刷三题(day13):ISBN号码+kotori和迷宫+矩阵最长递增路径
    题目一:ISBN号码题目描述:每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。ISBN码的首位数字表示书籍的出版语......
  • 算法打卡 Day18(二叉树)-层序遍历 + 翻转二叉树 + 对称二叉树
    文章目录层序遍历相关题目Leetcode226-翻转二叉树题目描述解题思路Leetcode101-对称二叉树题目描述解题思路层序遍历我们使用队列模拟二叉树的层序遍历。相关题目102.二叉树的层序遍历classSolution{public:vector<vector<int>>levelOrder(TreeNode......
  • 算法打卡 Day14(二叉树)-理论基础 + 递归遍历 + 迭代遍历 + 统一迭代
    文章目录理论基础满二叉树完全二叉树二叉搜索树平衡二叉搜索树二叉树的存储方式链式存储顺序存储二叉树的遍历方式二叉树的定义递归遍历leetcode144-二叉树的前序遍历leetcode145-二叉树的后序遍历leetcode94-二叉树的中序遍历迭代遍历前序遍历后序遍历中序遍历统......
  • Day1
    今天开始进行为期两个月的代码随想录刷题,并在此更新我的做题记录,也期望博客能成为我记录学习的一个好习惯。第一章为数组,也叫做顺序表,它的最大特点就是顺序存储且地址连续。第一道题为二分查找,该方法只适用于数组中元素的大小有序的情况下,基本原理大概为:当给定一个数组以及一个......
  • loj#575. 「LibreOJ NOI Round #2」不等关系
    记事件\(A\)为「当\(s_i=\texttt<\)时\(p_i<p_{i+1}\)」,事件\(B\)为「当\(s_i=\texttt<\)时\(p_i<p_{i+1}\),且存在\(s_j=\texttt>\),满足\(p_i<p_{i+1}\)。所求即\(n(A)-n(B)\)。\(n(A)\)是好求的,相当于部分定序排列,记每个递增段的长度为\(a_1......
  • Testing Egineer note:2024_5_20-day12-part01
    管理工具禅道一、禅道的介绍(1)定义禅道是一个项目管理工具,也是一个bug管理工具,还是一个用例管理工具。(2)作用:为了解决众多企业在管理中出现混乱,无序的现象,开发出来(3)来源:禅道属易软天川公司(4)禅道是集于产品管理,项目管理,测试管理于一身,同时包含事务管理,组织管理8众多功能,是中小企......
  • loj#566. 「LibreOJ Round #10」yanQval 的生成树
    \(\mu\)取值即所选边权的中位数。把每条边拆成两条(黑边和白边),边权分别为\(\mu-w_i\)和\(w_i-\mu\),要求黑边和白边各选\(\left\lfloor\dfrac{n-1}2\right\rfloor\)条,求最大生成树。可以直接wqs二分,时间复杂度\(\mathcalO(nm\logw~\alpha(n))\)。把所有边的边权......
  • loj#546. 「LibreOJ β Round #7」网格图
    裸的01BFS,时间复杂度\(\mathcalO(nm)\)。相邻的无障碍行可以缩成一行,列同理,所以全图的规模可以缩成\((k+1)\times(k+1)\),再01BFS,时间复杂度\(\mathcalO(k^2)\)。进一步地,所有\(1\timest\)或\(t\times1\)大小的无障碍连通块均可缩成一个点,两个连通块相交,则......
  • loj#523. 「LibreOJ β Round #3」绯色 IOI(悬念)
    由题述,\(X\)满匹配,根据Hall定理,有对于任意一个有\(k\)个妹子的集合,她们能配对的男生的人数\(\gek\)。把每个妹子看作她所连接的两个(可能是同一个)男生间的无向边,则每个连通块必然是树或基环树。问题转化为给每条无向边定向,满足每个点的入度不超过\(1\),求最大边权和。对......
  • react-day1
    1.react特点1.声明式2.组件化3.一次编写,跨平台4.单向数据流5.虚拟DOM6.Diff算法2.脚手架搭建项目npxcreate-react-appmy-appcdmy-appnpmstart3.语法规则1.根元素只能有一个2.jsx中使用使用js表达式,表达式写在{}中......