首页 > 其他分享 >[CEOI2009] photo 题解

[CEOI2009] photo 题解

时间:2024-08-16 16:16:49浏览次数:6  
标签:return int 题解 110 放置 photo Theta 矩形 CEOI2009

前言

题目链接:洛谷

好多错解都被我叉了,所以来贡献一发正确的题解,并予以解释。

题意简述

平面上有 \(n\) 个点,现在要求用最少的底边在 \(x\) 轴上且面积小于等于 \(S\) 的矩形覆盖所有点,这些矩形可以重叠。问最少矩形数量。矩形顶点不必是整点。

\(n \leq 100\)。

题目分析

没什么头绪。 你想瞎搞贪心?那就在洛谷上愉快 A 掉这道题吧!(洛谷上管理还没加数据。)

先来找找性质。离散化是 naive 的,然后套路地,对于 \(x\) 相同的点,只保留纵坐标最大的,这是显然的。假设我们放置了一个矩形 \(x \in [l, r]\),那么一个显然不劣的贪心是让这个矩形的高度为 \(\cfrac{S}{r-l}\),原因是能够包括更多的点。于是问题就变成了找出符合答案的若干区间,尝试用区间 DP 解决。

如果只记 \(f[l][r]\) 似乎并不好转移,故再记一维 \(h\),用 \(f[l][r][h]\) 表示 \([l, r]\) 区间内不低于 / 不高于 \(h\) 的点都被覆盖了。这两者似乎是等价的,但是后者是错误的,会在之后分析,这里使用前一种定义。

先来考虑边界情况。记 \(h_i\) 表示 \(x=i\) 时对应纵坐标。当 \(x \in [l, r]\) 里,所有 \(h_x\) 均比 \(h\) 小时,\(f[l][r][h] = 0\);以及当只有一个点处在 \(h\) 及上方,显然只用一个矩形就可以了。

考虑放置一个矩形。套路化地,我们只放置这个区间最左边的矩形,这样是能考虑到所有情况的。即,我们放置一个矩形 \(x \in [l, o]\),计算出能覆盖哪些点,找出 \([l, o]\) 中不能被覆盖的最小纵坐标 \(h'\),则 \(f[l][r][h]\) 可以从 \(f[l][o][h'] + f[o + 1][r][h] + 1\) 转移而来。

当然,实现上的细节,比如当 \(o=l\) 时可能会除以 \(0\) 等不展开。

这么做的时间复杂度是 \(\Theta(n^5)\),很容易发现在放置矩形的时候有重复计算,\(\Theta(n^3)\) 预处理 \(mi[l][r]\) 表示放置一个矩形 \(x \in [l, r]\),\(l \sim r\) 里没被覆盖的最小纵坐标,可以做到 \(\Theta(n^4)\) 的时间复杂度。当然,预处理可以是 \(\Theta(n ^ 2 \log n)\),但是没必要。

当然可以继续优化……常数。比如,找到满足 \(h_{l \sim L} < h\) 的最大 \(L\),同理最小的 \(R\),如果 \(L \neq l \lor R \neq r\),那么 \(f[l][r][h]\) 和 \(f[L][R][h]\) 显然是等价的。边界所有 \(h_x\) 均小于 \(h\) 等价于 \(L > R\),只有一个点等价于 \(L = R\)。把循环换成记忆化搜索能避免很多不必要的状态。

话说回来,为什么不能记不高于呢?我们很容易发现,如果放置了一个矩形,我们无法表示其上方剩余的点这种状态,所以是错误的。

时间复杂度:\(\Theta(n ^ 4)\),空间复杂度:\(\Theta(n ^ 3)\)。

代码

正解里 rank1

// #pragma GCC optimize(3)
// #pragma GCC optimize("Ofast", "inline", "-ffast-math")
// #pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int n, S;
int x[110], y[110];
int rx[110], ry[110];
int cx, cy;
int hign[110];

int f[110][110][110];  // [l, r] >= h 都好了的
int mi[110][110];  // [l, r] 放置矩形,不能被覆盖到的最小纵坐标

int dfs(int l, int r, int h) {
    if (l > r) return 0;
    if (~f[l][r][h]) return f[l][r][h];
    f[l][r][h] = n;
    int L = l, R = r;
    while (L <= R && hign[L] < h) ++L;
    while (R >= L && hign[R] < h) --R;
    if (L > R) return f[l][r][h] = 0;
    if (L == R) return f[l][r][h] = 1;
    if (L != l || R != r) return f[l][r][h] = dfs(L, R, h);
    for (int x = L; x <= R; ++x)
        f[l][r][h] = min(f[l][r][h], dfs(L, x, mi[L][x]) + dfs(x + 1, R, h) + 1);
    return f[l][r][h];
}

signed main() {
	scanf("%d%d", &n, &S);
	for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &x[i], &y[i]);
		rx[i] = x[i], ry[i] = y[i];
	}
	sort(rx + 1, rx + 1 + n);
	sort(ry + 1, ry + 1 + n);
	cx = unique(rx + 1, rx + 1 + n) - rx - 1;
	cy = unique(ry + 1, ry + 1 + n) - ry - 1;
	for (int i = 1; i <= n; ++i) {
		x[i] = lower_bound(rx + 1, rx + 1 + cx, x[i]) - rx;
		y[i] = lower_bound(ry + 1, ry + 1 + cy, y[i]) - ry;
	}
	for (int i = 1; i <= n; ++i) {
		hign[x[i]] = max(hign[x[i]], y[i]);
	}
	n = cx;
	for (int l = 1; l <= n; ++l) {
		mi[l][l] = n + 1;
		for (int r = l + 1; r <= n; ++r) {
			mi[l][r] = n + 1;
			int mxh = S / (rx[r] - rx[l]);
			for (int i = l; i <= r; ++i)
				if (ry[hign[i]] > mxh)
					mi[l][r] = min(mi[l][r], hign[i]);
		}
	}
    memset(f, 0xff, sizeof f);
    printf("%d", dfs(1, n, 1));
	return 0;
}

后记

一道初看毫无头绪的题目,根据小贪心发现和区间有关,使用区间 DP,再多记一维高度,然后套路地转移。

标签:return,int,题解,110,放置,photo,Theta,矩形,CEOI2009
From: https://www.cnblogs.com/XuYueming/p/18362659

相关文章

  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    题目传送门前置知识树链剖分|树的直径|最近公共祖先|并查集解法正着删边不太可做,考虑离线下来反着加边。一个显而易见的结论:设点集\(A\)的直径的两个端点为\(u_{1},v_{1}\),另一个点集\(B\)的直径的两个端点为\(u_{2},v_{2}\),则\(A\bigcupB\)的直径端点一定是......
  • 启动应用程序出现pcsvDevice.dll找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个pcsvDevice.dll文件(挑选合适的版本文件)把......
  • P6109 [Ynoi2009] rprmq1 题解
    Description有一个\(n\timesn\)的矩阵\(a\),初始全是\(0\),有\(m\)次修改操作和\(q\)次查询操作,先进行所有修改操作,然后进行所有查询操作。一次修改操作会给出\(l_1,l_2,r_1,r_2,x\),代表把所有满足\(l_1\lei\ler_1\)且\(l_2\lej\ler_2\)的\(a_{i,j}\)元......
  • 题解:P10688 Buy Tickets
    题目大意排队时有人插队。输入格式给定队列长度$n$。接下来$n$行每行两个正整数,第一个表示该元素插入位置,另一个表示该元素的权值。输出格式按照顺序输出该位置元素的权值。注意事项输入的数据组数未知,需要一直输入,输入方法可以参考以下代码。while(cin>>n){......
  • 题解:P10781 【MX-J1-T1】『FLA - III』Spectral
    P10781【MX-J1-T1】『FLA-III』Spectral题解(非正解,正解应该是数学题。)这道题很简单,分析题意就可以得出核心代码:for(inti=1;i<=n;i++){ans=k+ans/i;}那么恭喜你获得$40$pts。为什么呢?因为题目需要的是最高温度,而烧碳获得的温度可能小于烧炭时减低的温度。简单说......
  • JOISC2020 Day 4 A 首都 题解
    JOISC2020Day4A首都JOIAtCoderLuogu考虑一条链的情形。如图,将每个城市视为一条线段,容易发现交错(有交但不包含)的若干线段必须全部合并才能符合条件。但如果这么写会出错,原因是线段有包含关系,外层线段需要统计内层线段的答案,但内层线段不需要统计外层线段的答案。如果设内......
  • 题解:AT_abc365_d [ABC365D] AtCoder Janken 3
    D-AtCoderJanken3题解题意:高桥和青木要玩石头剪刀布,给你一个长度为\(n\)的字符串\(s\),\(s\)表示青木在第\(i\)局游戏中的动作(R表示石头,P表示布,S表示剪刀。)。高桥不可以在任何一局中输给青木(即:高桥和青木只可以平局或高桥赢青木),且高桥第\(i\)局出的和第\(i-1\)局......
  • 题解:P10313 [SHUPC 2024] 占地斗士!
    题目大意给出一个由.和#组成的\(n\timesm\)矩阵,然后再给你这\(4\)种图像,用着四种图像对矩阵进行覆盖(每个只能用一次)。其中,#的位置不可以被图像遮挡,也不能放在不能放置的格子上。解题思路考虑使用爆搜。第一个图像:if(mp[i][j]!='#'&&mp[i+1][j+1]!='#'......
  • 题解:P10111 [GESP202312 七级] 纸牌游戏
    题目大意给出三个序列:\(a\),\(b\),\(c\)分别表示:分数,罚分以及小杨从第\(1\)轮至第\(......
  • 题解:AtCoder Janken 3
    D-AtCoderJanken3题解题意高桥和青木要玩石头剪刀布,给你一个长度为\(n\)的字符串\(s\),\(s\)表示青木在第\(i\)局游戏中的动作(R表示石头,P表示布,S表示剪刀)。高桥不可以在任何一局中输给青木(即:高桥和青木只可以平局或高桥赢青木),且高桥第\(i\)局出的和第\(i-1\)局......