题意
题解
这个题一开始没有思路,看了看dls讲解感觉好厉害
我们先分析这个式子,这个式子带有绝对值,在图上的情况只有两种,左下角到右上角,右下角到左上角
那么我们分情况化简式子
会发现我们如果固定一个点,找到这个点的另一半区域的最小值来计算就可以了
以左边的情况为例,利用前缀和思想,维护 s [ i ] [ j ] s[i][j] s[i][j]代表以i和j为右下角的 a i , j − c ∗ ( i + j ) a_{i,j}-c*(i+j) ai,j−c∗(i+j)的最小值
这样对于每一个点就只需要计算一遍即可,时间复杂度由暴力的 O ( n 4 ) O(n^4) O(n4)变为 O ( n 2 ) O(n^2) O(n2)
可以用前缀和思想是因为最小值是可以重复贡献的
另一种情况就类似了,注意此时维护的是该点的左下角的矩阵
Code
int T;
ll n, m, c;
ll a[1010][1010];
ll s[1010][1010];
void solve(){
cin >> n >> m >> c;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cin >> a[i][j];
}
}
memset(s, 0x3f, sizeof(s));
ll res = 1e18; // 0x3f3f3f3f比memset的值要小,这里也可用设为0x3f3f3f3f3f3f3f3f
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
res = min(res, a[i][j] + c * (i + j) + min(s[i - 1][j], s[i][j - 1]));
s[i][j] = min({s[i - 1][j], s[i][j - 1], a[i][j] - c * (i + j)});
// cout << s[i][j] << ' ';
}
// cout << endl;
}
memset(s, 0x3f, sizeof(s));
for (int i = n; i >= 1; i--){
for (int j = 1; j <= m; j++){
res = min(res, a[i][j] + c * (j - i) + min(s[i][j - 1], s[i + 1][j]));
s[i][j] = min({s[i + 1][j], s[i][j - 1], a[i][j] + c * (i - j)});
}
}
cout << res;
}