求L-R的花销
令L不断减去D,令R不断减去D,直到结果小于等于D,最后得到的是同一个数(因为R是L加上一些D得到的)
最后得到的数在1-D之间
所以可以由 i (i : 1~D) ,计算出从i 到 i+D ,i+2D ....的花销,直到 i+nD>HW
将每个 i 到 x的花销,记作 dp[x] (叫pref前缀和可能更合适)
答案可以计算成:dp[R]-dp[L]
此时的复杂度:因为每个数值只被计算一次,所以 HW 为复杂度
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=300*300+5;
int h,w,d,q;
struct position{
int x,y;
}p[maxn];
int dp[maxn];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
//freopen("D:\in.txt","r",stdin);
cin>>h>>w>>d;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
int x;cin>>x;
p[x].x=i;
p[x].y=j;
}
}
//因为答案具有可拆解性质,所以可以预处理出所有dp[x],并且通过O(1)复杂度计算得到答案
for(int i=1;i<=d;i++){
for(int j=i+d;j<=h*w;j+=d){
dp[j]=dp[j-d]+abs(p[j-d].x-p[j].x)+abs(p[j-d].y-p[j].y);
}
}
cin>>q;
for(int i=1;i<=q;i++){
int l,r;cin>>l>>r;
cout<<dp[r]-dp[l]<<"\n";
}
return 0;
}