Jzoj5453【NOIP2017提高A组冲刺11.5】好路线
nodgd在旅游。现在,nodgd要从城市的西北角走到东南角去。这个城市的道路并不平坦,nodgd希望找出一条相对比较好走的路。
nodgd事先已经得到了这个城市的地图。地图上这个城市是一个n×m的矩形,nodgd现在站在坐标为(1,1)的位置,需要到达坐标为(n,m)的位置。这张地图上用非负整数标记了每个整数坐标点的海拔,坐标为(x,y)的位置的海拔是h(x,y)。nodgd希望找出一条路线,路线中任意时刻都在向正东或向正南走,而且只在整数坐标点的地方转弯,使得路上经过的n+m−1个整数坐标点的海拔的方差最小。然而万能的nodgd当然知道该怎么走,也当然知道方差最小是多少,只是想顺便考考你。
假如有k个实数x1,x2,…,xk,则平均值x'定义为Σxi/k
方差q^2定义为Σ(x'-xi)^2/k
在本题中为了方便,你只需要求出(n+m−1)^2×q^2的最小值即可,众所周知这是个整数。
对于30%的数据,1≤n,m≤10;
对于50%的数据,1≤n,m≤20;
对于100%的数据,1≤n,m≤50,0≤h(n,m)≤50。
今天题目最水的一道
第三题的树hash打挂了,第一题看错题(好多人看错了,100000级别的最大团?!)
好先来说说这道题
我们发现式子可以化简为(n+m-1)*Σxi^2-(Σxi)^2
考虑到(Σxi)很小,可以丢入dp状态中
设f[i][j][k]表示做到i,j这个点,(Σxi)为k的情况,(n+m-1)*Σxi^2的最小值
那么答案为min{f[n][m][k]-k^2}
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
using namespace std;
int n,m,v[60][60],c;
LL f[2][60][5010],res=1ll<<60;
inline LL sqr(int x){ return x*x; }
int main(){
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
memset(f,0x63,sizeof f);
scanf("%d%d",&n,&m); c=n+m-1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",v[i]+j);
f[1][1][v[1][1]]=sqr(v[1][1])*c;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(i>1 || j>1)
for(int k=5000;k>=v[i][j];--k)
f[i&1][j][k]=min(f[~i&1][j][k-v[i][j]],f[i&1][j-1][k-v[i][j]])+sqr(v[i][j])*c;
for(int k=5000;k>=v[n][m];--k) res=min(res,f[n&1][m][k]-sqr(k));
printf("%d\n",res);
}