P6818 [PA2013]Działka 题解

Posted xztx666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P6818 [PA2013]Działka 题解相关的知识,希望对你有一定的参考价值。

P6818 [PA2013]Działka

前言

我太菜了。。。。

对着 jiangly 大佬的题解研究了一下午研究了一下午才搞出来(泪目。

作为一个蒟蒻,我就详细的讲一下我对与本题的理解。

题意

本题的的题意描述的还是比较明了。

在二维坐标系中,输入 \\(n\\) 个点 \\(m\\) 次询问,

每次询问,给出一个矩阵,

求出矩阵内极大凸包的面积。

题解

1.如何求面积

二维平面的计算几何题,较常见的做法就是利用叉积。本题亦如此。

叉积有个优美的性质,我们可以发现对于 \\(\\veca \\times \\vecb\\) 可以在二维平面赋予特殊意义( \\(S\\) 为三角形面积)。

\\(\\veca \\times \\vecb = 2S\\)

利用这个性质我们就可以求出任意凸包的面积。

举个例子,\\(4\\) 个点坐标为 \\((1 , 1) (1 , 3) (3 , 3) (3 , 1)\\) 在此记为 \\(0\\) 号点到 \\(3\\) 号点,\\(G\\) 记为原点,

那要求出其凸包的面积就可以写作:

\\( \\vecG0 \\times \\vecG3 + \\vecG3 \\times \\vecG2 + \\vecG1 \\times \\vecG0 + \\vecG1 \\times \\vecG0 \\over 2\\)

其实就可以理解为绿色的三角形相加。

再容斥一下减去红色三角(由于叉乘的顺寻原因出来的红色三角形负数)。

剩下的就是索要求的凸包面积。

因为本题 \\(n \\le 3000\\) 我们可以考虑直接 \\(O(n ^ 2)\\) 预处理出每两个向量的叉乘(其实不是任意两个的叉乘,详见第三部分)。

呢么下面的任务就是快速找到凸包外面的点。


2.如何找凸包

如何找凸包呢?有一个十分优雅的方法。可以考虑寻找类似于四分之一扇形的凸包,然后每次旋转找到 \\(4\\) 个半圆再求和。假设我们先找右上角的扇形。

对于如下图形如何优美的找到凸包呢?

我们可以考虑将点以优先 \\(x\\) 从大到小后 \\(y\\) 从大到小的顺序找(过程可以顺便预处理前面提到的任意两点的距离)。

手模一下发现,我们先会从 \\(1\\) 号点就可以轻易的找到 \\(1 , 3 , 4\\) 的点集。

呢如何记录高效的记录答案呢?


3.如何记录答案

直接枚举每个问题,显然会 T 飞。

考虑在记录两点间距离的时候直接记录最外面凸包的距离,例如前面的图片,在记录 \\(\\vec1 \\times \\vec4\\) 的时可以直接记录为 \\(\\vec1 \\times \\vec3 + \\vec3 \\times \\vec4\\)。样我们在统计答案的时候实际上只需要记录只需要记录他最接近边界的两个点就可了。

考虑每一次记录答考虑使用线段树加扫描线的思想,如下图为每个点。

当我们更新完最外面的橙色的点还没有处理蓝色的点的时候,考虑有哪些区间里的提问是可以被更新的。

黄色的区间是可以被更新的,利用扫描线的思想做到 \\(O(m \\log m)\\) 维护每个图形的边界。


\\(\\bullet\\) 加强版

模拟赛出了这道题的加强版,若坐标的范围改成 \\(-10^7 \\le x ,y \\le 10^7\\)

两个办法,一是使用效率更高的 zkw 线段树,二是数据离散化。

当然本题用普通线段树就可以切了。

Code

代码跟 jiangly 大佬的没有本质区别,就不粘了(doge去翻上一篇题解吧。

如何根据R中的最后一行在所选行中添加前缀

【中文标题】如何根据R中的最后一行在所选行中添加前缀【英文标题】:how to add prefix in selected rows according to the last row in R 【发布时间】:2020-04-21 03:15:17 【问题描述】:

我有一个这样的数据框:

 Target Time ...
  pa     1   
  pa     2
  pa     3
  pa     4
  pa     5
  pa     6
  pa     7
  pa     8
  pa     9
  pa     10
  li     11
  li     12
  li     13
  li     14
  li     15
  li     16
  li     17
  li     18
  li     19
  li     20
  ka     1   
  ka     2
  ka     3
  ka     4
  ka     5
  ka     6
  ka     7
  ka     8
  ka     9
  ka     10
  li     11
  li     12
  li     13
  li     14
  li     15
  li     16
  li     17
  li     18
  li     19
  li     20
  pha     1   
  pha     2
  pha     3
  pha     4
  pha     5
  pha     6
  pha     7
  pha     8
  pha     9
  pha     10
  le     11
  le     12
  le     13
  le     14
  le     15
  le     16
  le     17
  le     18
  le     19
  le     20
..."

我想根据 1~10 的目标在 11~20 的目标之前添加一个前缀。我希望的是:

 Target Time ...
  pa     1   
  pa     2
  pa     3
  pa     4
  pa     5
  pa     6
  pa     7
  pa     8
  pa     9
  pa     10
  pa_li     11
  pa_li     12
  pa_li     13
  pa_li     14
  pa_li     15
  pa_li     16
  pa_li     17
  pa_li     18
  pa_li     19
  pa_li     20
  ka     1   
  ka     2
  ka     3
  ka     4
  ka     5
  ka     6
  ka     7
  ka     8
  ka     9
  ka     10
  ka_li     11
  ka_li     12
  ka_li     13
  ka_li     14
  ka_li     15
  ka_li     16
  ka_li     17
  ka_li     18
  ka_li     19
  ka_li     20
  pha     1   
  pha     2
  pha     3
  pha     4
  pha     5
  pha     6
  pha     7
  pha     8
  pha     9
  pha     10
  pha_le     11
  pha_le     12
  pha_le     13
  pha_le     14
  pha_le     15
  pha_le     16
  pha_le     17
  pha_le     18
  pha_le     19
  pha_le     20
...

我认为我需要先循环遍历数据并使用条件语句,所以我尝试了:

for (i in 1:nrow(df))
  ifelse (df$Time < 11,prev<-df$Target,df$Target<-paste(prev, df$Target,sep = "_"))
  print(df)

但它不起作用......我想知道我的逻辑是否正确或语句有问题? .. 我是 R 新手,真的希望有人能提供帮助!非常感谢!!

【问题讨论】:

请修正您的格式。 【参考方案1】:

你可以试试这个矢量化矢量回收方法:

inds <- rep(c(FALSE, TRUE), each = 10)
df$Target[inds] <- paste(df$Target[rev(inds)], df$Target[inds], sep = "_")

#   Target Time
#1      pa    1
#2      pa    2
#3      pa    3
#4      pa    4
#5      pa    5
#6      pa    6
#7      pa    7
#8      pa    8
#9      pa    9
#10     pa   10
#11  pa_li   11
#12  pa_li   12
#13  pa_li   13
#14  pa_li   14
#15  pa_li   15
#16  pa_li   16
#17  pa_li   17
#18  pa_li   18
#19  pa_li   19
#20  pa_li   20
#21     ka    1
#...

数据

在尝试上述解决方案之前,请确保 Target 列是字符而不是因素。

df <- structure(list(Target = c("pa", "pa", "pa", "pa", "pa", "pa", 
"pa", "pa", "pa", "pa", "li", "li", "li", "li", "li", "li", "li", 
"li", "li", "li", "ka", "ka", "ka", "ka", "ka", "ka", "ka", "ka", 
"ka", "ka", "li", "li", "li", "li", "li", "li", "li", "li", "li", 
"li", "pha", "pha", "pha", "pha", "pha", "pha", "pha", "pha", 
"pha", "pha", "le", "le", "le", "le", "le", "le", "le", "le", 
"le", "le"), Time = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 
11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 1L, 2L, 3L, 
4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 
18L, 19L, 20L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 
12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L)), row.names = c(NA, 
-60L), class = "data.frame")

【讨论】:

哇!非常感谢!!是的,我在尝试您的方法之前添加了 df$Target 【参考方案2】:

以后使用dput() 插入您的数据。它保留了打印输出没有的细节,例如 Target 是一个因素还是一个字符字段:

df <- structure(list(Target = c("pa", "pa", "pa", "pa", "pa", "pa", 
"pa", "pa", "pa", "pa", "pa_li", "pa_li", "pa_li", "pa_li", "pa_li", 
"pa_li", "pa_li", "pa_li", "pa_li", "pa_li", "ka", "ka", "ka", 
"ka", "ka", "ka", "ka", "ka", "ka", "ka", "ka_li", "ka_li", "ka_li", 
"ka_li", "ka_li", "ka_li", "ka_li", "ka_li", "ka_li", "ka_li", 
"pha", "pha", "pha", "pha", "pha", "pha", "pha", "pha", "pha", 
"pha", "pha_le", "pha_le", "pha_le", "pha_le", "pha_le", "pha_le", 
"pha_le", "pha_le", "pha_le", "pha_le"), Time = c(1L, 2L, 3L, 
4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 
18L, 19L, 20L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 
12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 1L, 2L, 3L, 4L, 
5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 
19L, 20L)), row.names = c(NA, -60L), class = "data.frame")

您的问题是您将矢量化函数 ifelse() 与循环混合在一起。正如@Ronak Shah 所示,您根本不需要循环。如果您想要循环,则需要使用ifelse 并逐行遍历:

for (i in 1:nrow(df))
  if (df$Time[i] < 11) prev <- df$Target[i]
        else df$Target[i]<-paste(prev, df$Target[i],sep = "_")

print(df[c(1:2, 11:12, 21:22, 31:32, 41:42, 51:52), ], right=FALSE)
#    Target Time
# 1  pa      1  
# 2  pa      2  
# 11 pa_li  11  
# 12 pa_li  12  
# 21 ka      1  
# 22 ka      2  
# 31 ka_li  11  
# 32 ka_li  12  
# 41 pha     1  
# 42 pha     2  
# 51 pha_le 11  
# 52 pha_le 12  

这种方法有效,但会比使用ifelse 慢。

【讨论】:

以上是关于P6818 [PA2013]Działka 题解的主要内容,如果未能解决你的问题,请参考以下文章

s5p6818 Overview

迅为LORA与S5P6818开发板物联网通讯方案

PA 2022 部分题解

「题解」PA2019 Terytoria

Tsinghua 2018 DSA PA3简要题解

题解P4025 [PA2014]Bohater