nodgd 好路线 noip 2015 模拟赛 T3

来源:互联网 发布:宁波大学网络注销 编辑:程序博客网 时间:2024/06/04 18:03

这里写图片描述

这里写图片描述

解析:

对于此题,我们选择从方差的表达式入手,我们已知k是经过的点的数目,而到达重点是经过了(n+m-1)个点,令N=(n+m-1),此时x(即海拔)的平均值为(x1+x2+x3+…+xN)/N,(为了方便,用x_来代替x的平均值),σ^2=((x1-x_)^2+(x2-x_)^2+…+(xN-x_)^2)/N,
而最终答案(n+m-1)^2*σ^2=N^2*σ^2,将原式带入得到答案 ans=N*(x1^2+…+xN^2)-(x1+…+xN)^2。
具体过程如下:
N^2*σ^2
=N*((x1-x_)^2+…+(xN-x_)^2)
=N*((x1^2-2*x1*x_)^2+…+(xN^2-2*xN*x_+x_^2))
=N*((x1^2+…+xN^2)-2*x_*(x1+…+xN)+N*(x_^2))
然后再将x_=(x1+…+xN)/N带入,即可得到ans表达式。
易得,在某点的ans为 当前经过的点的数目乘以那些点的高度的平方的和 再减去它们的高度的和的平方。(有点儿绕)
因此我们可以设定一个DP状态f[i][j][k],k表示到达点(i,j)时,经过的点的高度的和(只是和,没有平方!)(包括(i,j)),f[i][j][k]的值则表示它们的高度的平方和。
因此动态转移方程为:
f[i][j][k]=min(f[i-1][j][k-h[i][j]],f[i][j-1][k-h[i][j]])+h[i][j]^2.
讲到这就差不多了,贴代码!!

#include<stdio.h>#include<string.h> int f[51][51][5100];int h[51][51];int min(int x,int y){    return x>=y?y:x;}int pf(int x){    return x*x;}int main(){    int n,m;    int i,j,k;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++)        for(j=1;j<=m;j++)            scanf("%d",&h[i][j]);    memset(f,-1,sizeof(f));    f[1][0][0]=f[0][1][0]=0;    for(i=1;i<=n;i++){        for(j=1;j<=m;j++){            int s=(i+j-1)*50;   //高度和的上限            for(k=h[i][j];k<=s;k++){  //只是和,没有平方                if(f[i-1][j][k-h[i][j]]!=-1&&f[i][j-1][k-h[i][j]]!=-1)   //左边和上边的点都可以更新当前的点                    f[i][j][k]=min(f[i-1][j][k-h[i][j]],f[i][j-1][k-h[i][j]])+pf(h[i][j]);                else if(f[i-1][j][k-h[i][j]]!=-1)  //只有左边的点可以                    f[i][j][k]=f[i-1][j][k-h[i][j]]+pf(h[i][j]);                else if(f[i][j-1][k-h[i][j]]!=-1)  //只有上边的点可以                    f[i][j][k]=f[i][j-1][k-h[i][j]]+pf(h[i][j]);            }        }    }    int ans=1e9+9;    for(i=0;i<=(n+m-1)*50;i++)        if(f[n][m][i]!=-1)            ans=min(ans,(n+m-1)*f[n][m][i]-i*i);    printf("%d",ans);  //直接代入公式 N*(x1^2+...+xN^2)-(x1+...+xN)^2}
原创粉丝点击