zoukankan      html  css  js  c++  java
  • GDSOI2015 task2 覆盖半径

    题目大意

    一个(n imes m)的矩阵中有(p)个已经确定圆心的圆,并且每个格子有一定的分数,如果一个格子被任意一个或以上的圆覆盖,那么就可以得到这个格子的分数。现在求最小的半径,使得得分达到目标得分。

    算法1

    如果我们从二分答案入手,就可以得到一个判定性问题:给出一些半径相同的圆,求被它们覆盖的格子的分数总和。

    如果我们直接统计的话,时间复杂度为(O(n^2plog n)),做足常数优化的话,应该有(10)分。

    算法2

    对上面的进行改良,我们不使用太暴力的方法。我们可以把一个圆拆成若干宽度为(1)的矩形,或者说是条形的东西,然后对于每一列,我们可以得到若干区间来覆盖这一列的格子。

    这个我们可以对区间的首尾分别进行排序,然后从上往下扫一遍,记一个(cover),如果有区间进入就将(cover)加一,有出去的区间就减一。接着弄个部分和什么的,就可以得到这一列的得分了。

    时间复杂度:还是(O(n^2plog n))

    算法3

    直接用k-d树,期望时间复杂度(O((n^2log n + p) log n))

    算法4

    换一个思路,计算每个格子被覆盖时最小需要的半径,也就是找到距离这个格子最近的圆心。然后就可以线性的扫描一遍得到答案。

    评委给出的方法是,每一次计算一行格子的答案。对于一个在第(i)列的格子,计算它到最近的圆心(注意,圆心与这个格子必须在同一列)的距离,记为(a_i),显然这个是很容易计算的。然后对于位于第(i)列的格子,我们可以枚举(j),这时,这个格子的答案可以这样计算:(min_j {((i-j)^2+a_j)})(min_j (i^2+j^2-2ij+a_j))

    设一个截距(z= i^2+j^2-2ij+a_j),然后就是(2ij+z= i^2+j^2+a_j),把(2j)当作横坐标,(j^2+a_j)为纵坐标,就是典型的斜率优化。这里(i)递增,(2j)递增,所以这个可以在(O(n))的时间内完成。

    于是我们可以从左往右做一次,再从右往左做一次,就可以得到这一行的格子的答案了。

    总时间复杂度(O(n^2))

    算法5

    这是评讲时各路神犇提出的方法,同样要计算距离每个格子最近的圆心:

    对于每一个格子,记一个二元组((d,k)),表示距离这个格子最近的圆心是为(k),距离是(d)。于是,每个格子可以去更新其他格子。注意到(d)最小的格子是不可能被其他格子更新的,所以我们可以采用Dijkstra的思想,弄一个优先队列不断更新即可。

    时间复杂度:(O(n^2log n))

    算法6

    还是k-d树,期望时间复杂度(O(n^2log n))

    算法7

    维护一个凸壳,然后通过三分来找到最近的点。需要上下各做一次。

    时间复杂度:(O(n^2 log_{1.5} n))

    算法8

    这是zhx提出的随机化算法,考场上A掉了数据。

    先把塔random_shuffle一下,每次取一座塔,然后往四周宽搜更新格子最近的塔,当然,如果不能更新则不把该格子放入队列。据zhx所言,每个点期望被更新(log n)次,我也不知道怎么证明啊囧。所以总的时间复杂度是(O(n^2 log n)),感觉会很好写。

  • 相关阅读:
    PTA(Basic Level)1038.统计同成绩学生
    PTA(Basic Level)1026.程序运行时间
    PTA(Basic Level)1031.查验身份证
    PTA(Basic Level)1061.判断题
    Windows 常用命令
    Windows安装启动MySQL
    classpath路径配置
    IDEA远程调试
    Java Effective 读书笔记
    Try Catch Finally总结
  • 原文地址:https://www.cnblogs.com/wangck/p/4505005.html
Copyright © 2011-2022 走看看