AtCoder - abc089_d Practical Skill Test 分析

39 阅读1分钟

 求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;
}