题解 P4767 【[IOI2000]邮局】

SIGSEGV

2018-08-27 11:09:19

Solution

四边形不等式.......了解一下? 对于这种要枚举i,j,k,时间复杂度为O(n^3)的dp,使用mk[i][j]记录下k的值,会发现mk[i-1][j] <= k <= mk[i][j+1] (证明[在此](https://blog.csdn.net/u014800748/article/details/45750737)) 本题正常的DP方程很容易想到:dp[i][j]表示前j个村庄中建了i个村庄距离总和的最小值。 我们可以利用数学证明:在i~j之间建立邮局的位置选在中间一定最优,因此计算出在i~j之间建立邮局的最优值w[i][j],方程便可得出: ### dp[i][j] = max{dp[i][k] + w[k+1][j]} 时间复杂度O(N^3),优化后为O(N^2) 上代码 ```cpp #include <bits/stdc++.h> using namespace std; int n,m,a[3005],mk[3005][3005]; long long dp[305][3005],w[3005][3005]; int main () { scanf("%d%d",&n,&m); for (int i = 1;i <= n;i++) scanf("%d",&a[i]); sort(a + 1,a + n + 1);//先按坐标排序 for (int i = 1;i <= n;i++) for (int j = i + 1;j <= n;j++) w[i][j] = w[i][j - 1] + a[j] - a[(i + j) / 2];//计算w[i][j]的值 for (int i = 1;i <= n;i++) dp[1][i] = w[1][i],mk[1][i] = 0;//初始化 for (int i = 2;i <= m;i++) { mk[i][n + 1] = n;//这个值没有计算出来,因此预处理为n for (int j = n;j > i;j--) //因为在枚举k的时候需要mk[i][j+1]的值,因此倒序枚举j { dp[i][j] = 1ll << 60; for (int k = mk[i - 1][j];k <= mk[i][j + 1];k++) if (dp[i][j] > dp[i - 1][k] + w[k + 1][j]) dp[i][j] = dp[i - 1][k] + w[k + 1][j],mk[i][j] = k;//更新mk[i][j] } } printf("%lld",dp[m][n]); return 0; } ```