鱼C论坛

 找回密码
 立即注册
查看: 1789|回复: 22

[技术交流] P3145--题解(鱼币~)

[复制链接]
回帖奖励 1 鱼币 回复本帖可获得 1 鱼币奖励! 每人限 1 次(中奖概率 80%)
发表于 2024-8-23 09:52:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 学习编程中的Ben 于 2024-8-23 10:18 编辑

$题目链接:[USACO16OPEN] Splitting the Field G$

前言:

本蒟蒻第一篇题解, 存在问题的的地方还请各位多多包涵、指出。

核心思路
本题可以简化成在网格图中有 $n$ 个点,让你圈出 $2$ 个矩形,使得这 $2$ 个矩形面积最小。

1.建立矩阵

题目中指出所有坐标都是正数,于是我们可以 $(0, 0)$ 为锚点,从远到近将所有的点排序.再从第一个点开始枚举,将点的序列分为前后两部分。

$$ ans_{i} = S_{1, i} + S_{i + 1, n} $$

这样分可以将所有的点分成离锚点较近的和距离锚点较远的点,易证没有更优的分法。

2.求矩形面积

通过观察,我们可以发现矩形的长就是这些点中 最大的 $x$ 的值 减去 最小的 $x$ 的值,宽是这些点中 最大的 $y$ 的值 减去 最小的 $y$ 的值

那我们的问题可以转化成求区间内最值

数据范围是 $ 1 \le n \le 50000 $

我们要枚举每一个点,找到每一个点的最大和最小的 $x$ 和 $y$ 的值,所以需要对查找操作进行优化. 这里推荐使用 $RMQ$.不懂戳这儿 $RMQ$简单介绍

注意事项:
1. 我们应该将 $x, y$ 分别排序,取最小值(只对 $x$ 排序 $80$ 分)
2. 不开 $ long~long $ 见祖宗
3. $RMQ$ 要设置初始值
4. 求出 $ans$ 后要用整个矩形的面积减去 $ans$

代码如下:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, fx[50001][31][2], fy[50001][30][2], ans = 1e20, t, lx, ly, rx, ry;
struct cow{
        int x, y;
}a[50001];
bool cmp1(cow a, cow b){
        return a.x < b.x;
}
bool cmp2(cow a, cow b){
        return a.y < b.y;
}
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){ if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
void rmq(){
        for (int i = 0; i <= n; i++){
                for (int j = 0; j <= 30; j++){
                        fx[i][j][0] = fy[i][j][0] = 1e20;
                }
        }
        for (int i = 1; i <= n; i++) fx[i][0][0] = fx[i][0][1] = a[i].x, fy[i][0][0] = fy[i][0][1] = a[i].y;
        for (int j = 1; j <= 30; j++){
                for (int i = 1; i + (1 << j) - 1 <= n; i++){
                        fx[i][j][0] = min(fx[i][j - 1][0], fx[i + (1 << j - 1)][j - 1][0]);
                        fx[i][j][1] = max(fx[i][j - 1][1], fx[i + (1 << j - 1)][j - 1][1]);
                        fy[i][j][0] = min(fy[i][j - 1][0], fy[i + (1 << j - 1)][j - 1][0]);
                        fy[i][j][1] = max(fy[i][j - 1][1], fy[i + (1 << j - 1)][j - 1][1]);
                }
        }
}
int find(int l, int r){
        t = log2(r - l + 1);
        lx = max(fx[l][t][1], fx[r - (1 << t) + 1][t][1]);
        rx = min(fx[l][t][0], fx[r - (1 << t) + 1][t][0]);
        ly = max(fy[l][t][1], fy[r - (1 << t) + 1][t][1]);
        ry = min(fy[l][t][0], fy[r - (1 << t) + 1][t][0]);
        return (lx - rx) * (ly - ry);
}
signed main() {
        n = read();
        for (int i = 1; i <= n; i++) a[i].x = read(), a[i].y = read();
        sort(a + 1, a + 1 + n, cmp1);
        rmq();
        for (int i = 1; i < n; i++){
                int k = find(1, i), q = find(i + 1, n);
                ans = min(ans, k + q);
        }
        sort(a + 1, a + 1 + n, cmp2);
        rmq();
        for (int i = 1; i < n; i++){
                int k = find(1, i), q = find(i + 1, n);
                ans = min(ans, k + q);
        }
        cout << find(1, n) - ans;
        return 0;
}


博客食用味更佳: 传送门
去我博客支持一下嘿嘿嘿.毕竟是蒟蒻第一篇题解.管理员还在审核.

@liuhongrun2022 @歌者文明清理员 @~风介~ @zhangjinxuan @不二如是 @柿子饼同学 @陶远航
求评分~(快升级了!!!)

评分

参与人数 3荣誉 +14 鱼币 +11 贡献 +8 收起 理由
Wei-Yuanzhe + 1 + 1 还给你 :P
柿子饼同学 + 5 + 5 orz
~风介~ + 8 + 5 + 8 冲冲冲

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-8-23 09:58:52 | 显示全部楼层
所以说原来是可以LaTeX的。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-23 09:58:58 | 显示全部楼层
你好,鱼油!

你的题目思路基本上是对的,下面我来帮你简洁的解答一下这个问题。

### 核心思路
P3145题目可以简化为在网格图中分割n个点,使得用两个矩形圈出的面积最小。

### 具体步骤
1. **排序**:
   - 由于坐标全是正数,可以以(0, 0)为锚点,对所有点按照某个规则排序(如先按x坐标,再按y坐标排序)。

2. **枚举分割点**:
   - 从第一个点开始,尝试将点的序列分为前后两部分,即前i个点和后n-i个点。

3. **计算矩形面积**:
   - 对每一部分,分别求出所包含点集的最小和最大x值、y值。
   - 矩形面积就等于(最大x - 最小x) * (最大y - 最小y)。

4. **更新最小面积**:
   - 对于每一种划分方法,计算两部分的矩形面积总和,并取其中的最小值。

### 算法实现简要描述
def min_area(points):
    points.sort()  # 根据题意先排序所有点
    
    min_total_area = float('inf')
    
    for i in range(1, len(points)):
        left_part = points[:i]
        right_part = points[i:]
        
        # 计算左部分矩形的边界
        min_x1 = min(point[0] for point in left_part)
        max_x1 = max(point[0] for point in left_part)
        min_y1 = min(point[1] for point in left_part)
        max_y1 = max(point[1] for point in left_part)
        
        # 计算右部分矩形的边界
        min_x2 = min(point[0] for point in right_part)
        max_x2 = max(point[0] for point in right_part)
        min_y2 = min(point[1] for point in right_part)
        max_y2 = max(point[1] for point in right_part)
        
        # 计算面积
        area1 = (max_x1 - min_x1) * (max_y1 - min_y1)
        area2 = (max_x2 - min_x2) * (max_y2 - min_y2)
        
        # 更新最小面积
        min_total_area = min(min_total_area, area1 + area2)
    
    return min_total_area

以上算法的时间复杂度为 \(O(n \log n)\)(排序) + \(O(n^2)\)(枚举分割和计算面积),在n较小时是可行的。可以通过更复杂的数据结构优化最小最大值的计算以实现进一步的性能提升。

希望这个回答能帮助你更好地理解和解决这个问题。如果有不清楚的地方,欢迎继续提问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-23 10:14:45 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-8-23 15:07:33 | 显示全部楼层
谢谢啦~@~风介~
等了好久都没几个人回复,评分
现在论坛怪冷清的.以前这种有鱼币的帖子回复率还是挺高的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-23 20:27:34 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-8-23 21:25:10 | 显示全部楼层
d
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-8-24 11:44:44 | 显示全部楼层

回帖奖励 +1 鱼币

&#128076;
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-24 18:05:41 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-8-29 09:20:21 | 显示全部楼层

回帖奖励 +1 鱼币

膜拜orz
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-31 16:44:50 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-1 09:55:47 | 显示全部楼层

回帖奖励 +1 鱼币

看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-4 16:01:51 | 显示全部楼层

回帖奖励 +1 鱼币

谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-4 17:15:02 | 显示全部楼层
.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-5 22:43:18 | 显示全部楼层

回帖奖励 +1 鱼币

OIer 居然跑到这来发题解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-9 10:57:15 | 显示全部楼层

回帖奖励 +1 鱼币

看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-13 20:26:46 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-14 13:02:49 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-9-14 17:42:08 | 显示全部楼层
谢谢鱼币
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-21 21:18:58 | 显示全部楼层

回帖奖励 +1 鱼币

没看懂怎么办
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 01:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表