P9272 [CEOI 2013] 千岛之国 / Adritic 题解

手玩一下样例和一些小一点的数据发现,在操作之后肯定只剩下左下角和右上角的两部分没有被遍历到,这跟题目保证的两个点肯定有相互到达的道路有关。

左下角和右上角是差不多的,这里就以左下角作为例子进行 dp。

\(dp_{i,j}\) 为需要解决 \((i,j)\) 及其左下角的矩形的最小花费,而当我们遍历到 \(dp_{i,j}\) 的时候,默认了 \((1,1) \sim (i+1,j)\)\((i,j+1)\sim (2500,2500)\) 这两个矩形里的岛屿肯定是被遍历过的,它们会对这里面的花费造成影响。而其他的格子就算又被遍历过也对矩形中的花费无影响。而这里的影响也是很好求的,矩形的上方的这些岛屿只有往右下跳才是有用的,而矩形右边的岛屿只有往左上跳才是有用的,可以贪心的去取这些点,上方取一个 \(y\) 最小的,右边取一个 \(x\) 最大的。会组成一个更小的矩形,\(dp_{i,j}\) 就等于这个小矩形的答案加上这个矩形的岛屿数量,因为至少需要一次跳跃才能调到下一个岛屿,这样就变成了一个形式相同,规模更小的子问题,同理的解决即可。当矩形中没有岛屿时就 \(dp_{i,j}=0\)

代码比较简短:

#include <bits/stdc++.h>
using namespace std;
const int N = 2505 + 5;
int n, mxx[N], mix[N], mxy[N], miy[N];
int f[N][N], g[N][N];
bool vis1[N][N], vis2[N][N];
int x[250005], y[250005], sum[N][N];
int F(int x, int y) {
    if (vis1[x][y])
        return f[x][y];
    vis1[x][y] = 1;
    if (sum[x][2500] - sum[x][y - 1] == 0)
        return f[x][y] = 0;

    return f[x][y] = sum[x][2500] - sum[x][y - 1] + F(min(x, mix[y - 1]), max(y, mxy[x + 1]));
}
int G(int x, int y) {
    if (vis2[x][y])
        return g[x][y];
    vis2[x][y] = 1;
    if (sum[2500][y] - sum[x - 1][y] == 0)
        return g[x][y] = 0;
    return g[x][y] = sum[2500][y] - sum[x - 1][y] + G(max(x, mxx[y + 1]), min(y, miy[x - 1]));
}
int main() {
    scanf("%d", &n);
    memset(mix, 0x3f, sizeof mix);
    memset(miy, 0x3f, sizeof miy);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", x + i, y + i);
        sum[x[i]][y[i]]++;
        mxx[y[i]] = max(x[i], mxx[y[i]]);
        mix[y[i]] = min(x[i], mix[y[i]]);
        mxy[x[i]] = max(y[i], mxy[x[i]]);
        miy[x[i]] = min(y[i], miy[x[i]]);
    }
    for (int i = 1; i <= 2500; i++) mix[i] = min(mix[i - 1], mix[i]), miy[i] = min(miy[i - 1], miy[i]);
    for (int i = 2500; i; i--) mxx[i] = max(mxx[i + 1], mxx[i]), mxy[i] = max(mxy[i + 1], mxy[i]);
    for (int i = 1; i <= 2500; i++)
        for (int j = 1; j <= 2500; j++) sum[i][j] += sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
    for (int i = 1; i <= n; i++) {
        cout << (n - 3 + F(x[i], y[i]) + G(x[i], y[i])) << endl;
    }
    return 0;
}
posted @ 2025-08-27 16:12  hnczy  阅读(16)  评论(0)    收藏  举报