题目链接:http://oj.daimayuan.top/course/22/problem/849
分析:采用暴力做法是O(n^4)。喜提TLE。
方法:二维前缀和优化O(n^2)
思路:通过题意可以知道:
我们把这个式子进行拆分一下(),
即:图解:A在B的右上方:这样做的目的,是消除绝对值符号
令:
这时,我们需要找W[i][j]的二维最小前缀和:
再暴力枚举一遍,即可求出最小值。
具体看代码:
#include <bits/stdc++.h>
#define pi acos(-1)
#define int long long
#define PII pair<int,int>
#define all(v) v.begin(),v.end()
#define INF 0x3f3f3f3f3f3f3f3f
#define fs(a) cout<<fixed<<setprecision(a)<< //fs(4)(1.0/3)=0.3333//保留a位小数
#define read() freopen("input.txt","r",stdin)
#define output() freopen("output.txt","w",stdout)
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e6+10;
const int mod = 1e9+7;
const int Mod = 998244353;
int up(int a,int b){return a<0?a/b:(a+b-1)/b;}// a/b向上取整
int n,m,c;
int a[2002][2002],W[2002][2002],X[2002][2002];
inline int solve(){
memset(W,INF,sizeof W);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
W[i][j]=a[i][j]-c*i-c*j;
W[i][j]=min(W[i][j],min(W[i-1][j],W[i][j-1]));/*寻找最小二维前缀
为了不多开一个二维数组,直接在W数组上进行操作吧*/
}
}
int ans=1e18;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
X[i][j]=a[i][j]+c*i+c*j;
ans=min(ans,X[i][j]+min(W[i-1][j],W[i][j-1]));//推理公式
}
}
return ans;
}
signed main(){
fast;
cin>>n>>m>>c;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
int ans=solve();
for(int i=1;i<=n;i++){
reverse(a[i]+1,a[i]+1+m);//把每行进行翻转//避免出现绝对值的情况
}
ans=min(ans,solve());//翻转前后都做一遍,取最小值
cout<<ans;
}