QOJ7199 Bomb

我们考虑对于前 \(i\) 个点观察其导出子图的形态。当前会形成若干强连通分量,假设总共有 \(k\) 个。

就一定需要满足其中第 \(i\) 个强连通分量能够到达第 \(i+1\) 个强连通分量,否则不管后面如何加点都于事无补。因此为了保证强连通分量的极大性,第 \(i\) 个强连通分量不能够到达地 \(i-1\) 个强连通分量。

考虑当前加入一个点 \(i\),对强连通分量产生的变化。

首先,需要满足限制:第 \(k\) 个强连通分量要能到达点 \(i\),不然必然不合法。

此外,加入点 \(i\) 可以看成是先将点 \(i\) 作为第 \(k+1\) 个连通块。然后我们找到当前 \(i\) 向左能够到达最远的强连通分量,假设是第 \(p\) 个,那么就可以将的 \(p\) 个强连通分量到第 \(k+1\) 个连通块合并。

由于我们需要满足上面提到的限制,所以一个暴力的想法是,我们记录每个强连通分量向右到达最远位置。此时,一个性质是,对于新连通块向右到达最远位置,一定是第 \(p\) 个强连通分量向右到达最远位置和点 \(i\) 向右到达最远位置的较大值。

这是因为,如果存在第 \(q(q>p)\) 个强连通分量向右到达最远位置比 \(i\) 远,那么说明存在一个点的半径比 \(i\) 大,由于它的坐标更左,所以理应在此之前就将第 \(p\) 个强连通分量合并了。

QQ20250219-102551


我们关注第一个连通块的信息,假设当前第一个连通块为前 \(i\) 个结点,且向右到达最远位置为 \(j\)(并且对于 \(i\ne n\),有 \(j>i\)),令前 \(i\) 个点半径平方和的最小值为 \(dp_{i,j}\)

假设下一次第一个连通块拓展位置为 \(k\),那么我们先声称 \(p\in[i+1\sim k-1]\) 这部分的点,半径一定为 \(a_{p+1}-a_p\)

QQ20250219-102610

现在,我们来说明一下这部分的最优性。首先,由于前面提到的性质,我们并不关注 \(i+1\sim k-1\) 这部分点的向右到达最远位置,当然也不关注它们向左到达的最远位置,仅仅只要求它们能作为连通的一部分就好了。

假设存在点 \(p\),满足点 \(p\) 到不了点 \(p+1\),那么此时一定有 \(l<p\)\(r\ge p+1\),存在 \(l\)\(r\) 的连边,那么此时其贡献为 \((a+b)^2\),多出了 \(b^2+2ab-c^2\) 的贡献,由于 \(b\ge c\),所以必然不优。

QQ20250219-103646

或者换一个角度理解,令点 \(p\) 向右到达最远位置为 \(nxt_p\),那么为了保证连通性,一定需要有 \([p,nxt_p]\) 能将 \([i+1,k-1]\) 覆盖满。

而我们将第 \(p\) 个点的半径为 \(a_{p+1}-a_p\) 不仅保证了总和是下界,同时还保证了已经分配得尽可能均匀,所以是最优的。


于是我们考虑转移,枚举点 \(k\) 的向右到达最远位置为 \(l\)

那么可以得到:

\[dp_{i,j}+\sum_{p=i+1}^{k-1}(a_{p+1}-a_p)^2+\max\{a_l-a_k,a_k-a_i\}^2\to dp_{k,\max\{j,l\}} \]

此时,我们就会意识到 \(j\) 的作用是为了限制时刻都满足过程中 \(j>i\),直到 \(i=n\)

现在,我们考虑优化转移,首先这个 \(\sum_{p=i+1}^{k-1}(a_{p+1}-a_p)^2\) 可以用前缀和轻松处理。我们对两个 \(\max\) 的取值分类讨论。

  1. \(\max\{j,l\}\) 的取值为 \(l\)

    这个时候,我们发现我们不关心 \(j\) 的取值,于是可以看成直接从 \(dp_{i,i+1}\) 转移得到。

    1. \(\max\{a_l-a_k,a_k-a_i\}\) 的取值为 \(a_l-a_k\)
      \(a_l-a_k\ge a_k-a_i\) 得到 \(a_i\ge 2a_k-a_l\)

      我们可以枚举 \(k\),再枚举 \(l\),双指针可行找到 \(i\) 的最大可行值为 \(pos\),预处理 \(g_p=\min_{t=p}^{i-1}dp_{t,t+1}\) 即可。

    2. \(\max\{a_l-a_k,a_k-a_i\}\) 的取值为 \(a_k-a_i\)

      那么我们可以枚举 \(k\),再枚举 \(i\),双指针找到 \(l\) 的最大值,最后求完之后对 \(dp_{i}\) 做一遍后缀 chkmin 即可;

  2. \(\max\{j,l\}\) 的取值为 \(j\)

    朴素的想法是,我们可以使用斜率优化。

    我们分析一下性质,发现由于过程中保持 \(j\) 不变,所以此时每次一定是从 \(i\) 转移到 \(i+1\)

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

暴力代码:

void zhk() {
    read(n);
    F(i, 1, n) read(a[i]);
    F(i, 2, n) s[i] = s[i - 1] + (ll) (a[i] - a[i - 1]) * (a[i] - a[i - 1]);
    F(i, 1, n)
        F(j, i, n)
            dp[i][j] = INF;
    F(i, 2, n) dp[1][i] = (ll) (a[i] - a[1]) * (a[i] - a[1]);
    F(i, 1, n - 1) {
        F(j, i + 1, n) {
            F(k, i + 1, n) {
                F(l, k, n)
                    chkmin(dp[k][max(j, l)], dp[i][j] + s[k] - s[i + 1] + (ll) max(a[l] - a[k], a[k] - a[i]) * max(a[l] - a[k], a[k] - a[i]));
            }
        }
    }
    cout << dp[n][n] << '\n';
}

转移优化代码:

void zhk() {
	read(n);
	F(i, 1, n) read(a[i]);
	F(i, 2, n) s[i] = s[i - 1] + (ll) (a[i] - a[i - 1]) * (a[i] - a[i - 1]);
	F(i, 1, n)
		F(j, i, n)
			dp[i][j] = INF;
	F(i, 2, n) dp[1][i] = (ll) (a[i] - a[1]) * (a[i] - a[1]);
	F(i, 2, n) {
		g[i] = INF;
		DF(j, i - 1, 1) g[j] = min(g[j + 1], dp[j][j + 1] - s[j + 1]);
		int pos = 1;
		DF(j, n, i) {
			while (a[i] - a[pos] > a[j] - a[i]) pos++;
			chkmin(dp[i][j], s[i] + g[pos] + (ll) (a[j] - a[i]) * (a[j] - a[i]));
			chkmin(dp[i][j], dp[i - 1][j] + (ll) (a[i] - a[i - 1]) * (a[i] - a[i - 1]));
		}
		pos = n;
		F(j, 1, i - 1) {
			while (a[pos] - a[i] > a[i] - a[j]) pos--;
			chkmin(dp[i][pos], s[i] - s[j + 1] + dp[j][j + 1] + (ll) (a[i] - a[j]) * (a[i] - a[j]));
		}
		DF(j, n - 1, i) chkmin(dp[i][j], dp[i][j + 1]);
	}
	cout << dp[n][n] << '\n';
}
posted @ 2025-02-19 10:58  zhaohaikun  阅读(142)  评论(0)    收藏  举报