【GDOI2017第二轮模拟day2】开房间
2017-04-16 22:36
375 查看
Description
A君与B君正在玩一款闯关游戏,游戏共有n关,每一关的目标只有一个:开房间。
每一关都会有m个房间(从1~m进行编号),A君与B君每关各打开一个房间即可过关,但两人不能打开同一个房间。
通过每一关后,m个房间会重新关上,在第i关打开第j个房间需要消耗t[i][j]的体力值。并且无论A君还是B君,除了第一关外,若上一关自己开了a号房间,这一关开了b号房间,则需要额外消耗K*|a-b|点体力值。
现在请你回答,两人过完全部n关后,所要消耗的体力值之和(两人消耗体力相加)最小能是多少。
Input
第一行三个整数n,m,K.
接下来n行每行m个整数,第i行第j个整数t[i][j]表示第i关开第j个房间需要消耗的体力值。
Output
仅一行一个整数表示答案。
Sample Input
3 3 10
2 13 4
4 3 2
16 4 3
Sample Output
28
Data Constraint
30%的数据:n,m <= 5
60%的数据:n,m <= 50
100%的数据:1 <= n,m <= 300 , 1 <= K,t[i][j] <= 10^6
我们考虑f[z,i,j]的贡献,容易发现是左上,右上,左下,右下四个方向的f[z-1,x,y]+k*曼哈顿距离+a[z,i]+a[z,j],最后两项可以最后再加上去,而前面的两项可以发现是一个二维的前缀和,所以我们可以从四个方向预处理前缀和,然后就可以O(1)算出当前位置的答案了
但是这样还是会超时,然后我们发现两个人的路径不会出现交叉的情况,那么我们强制i小于j,然后就可以把常数缩小一半,可以通过此题~
A君与B君正在玩一款闯关游戏,游戏共有n关,每一关的目标只有一个:开房间。
每一关都会有m个房间(从1~m进行编号),A君与B君每关各打开一个房间即可过关,但两人不能打开同一个房间。
通过每一关后,m个房间会重新关上,在第i关打开第j个房间需要消耗t[i][j]的体力值。并且无论A君还是B君,除了第一关外,若上一关自己开了a号房间,这一关开了b号房间,则需要额外消耗K*|a-b|点体力值。
现在请你回答,两人过完全部n关后,所要消耗的体力值之和(两人消耗体力相加)最小能是多少。
Input
第一行三个整数n,m,K.
接下来n行每行m个整数,第i行第j个整数t[i][j]表示第i关开第j个房间需要消耗的体力值。
Output
仅一行一个整数表示答案。
Sample Input
3 3 10
2 13 4
4 3 2
16 4 3
Sample Output
28
Data Constraint
30%的数据:n,m <= 5
60%的数据:n,m <= 50
100%的数据:1 <= n,m <= 300 , 1 <= K,t[i][j] <= 10^6
题解
一开始比赛的时候想到用堆把一个n优化成log,但是后来发现是道套路题我们考虑f[z,i,j]的贡献,容易发现是左上,右上,左下,右下四个方向的f[z-1,x,y]+k*曼哈顿距离+a[z,i]+a[z,j],最后两项可以最后再加上去,而前面的两项可以发现是一个二维的前缀和,所以我们可以从四个方向预处理前缀和,然后就可以O(1)算出当前位置的答案了
但是这样还是会超时,然后我们发现两个人的路径不会出现交叉的情况,那么我们强制i小于j,然后就可以把常数缩小一半,可以通过此题~
贴代码
var f:array[0..305,0..305,0..305]of longint; a,p1,p2,p3,p4:array[0..305,0..305]of longint; i,j,k,l,n,m,x,y,z,ans:longint; function min(x,y:longint):longint;inline; begin if x<y then exit(x) else exit(y); end; begin assign(input,'room.in'); reset(input); assign(output,'room.out'); rewrite(output); readln(n,m,k); for i:=1 to n do begin for j:=1 to m do read(a[i,j]); readln; end; fillchar(f,sizeof(f),$7f); for i:=1 to m do for j:=1 to m do if i<>j then f[1,i,j]:=a[1,i]+a[1,j]; fillchar(p1,sizeof(p1),$7f); p2:=p1; p3:=p1; p4:=p1; for z:=2 to n do begin for i:=1 to m-1 do for j:=i+1 to m do begin if p1[i,j-1]<p1[i-1,j] then p1[i,j]:=p1[i,j-1]+k else p1[i,j]:=p1[i-1,j]+k; if f[z-1,i,j]<p1[i,j] then p1[i,j]:=f[z-1,i,j]; end; for i:=m-1 downto 1 do for j:=i+1 to m do begin p2[i,j]:=f[z-1,i,j]; p2[i,j]:=min(p2[i,j],k+min(p2[i+1,j],p2[i,j-1])); end; for i:=1 to m-1 do for j:=m downto i+1 do begin p3[i,j]:=f[z-1,i,j]; p3[i,j]:=min(p3[i,j],k+min(p3[i-1,j],p3[i,j+1])); end; for i:=m-1 downto 1 do for j:=m downto i+1 do begin p4[i,j]:=f[z-1,i,j]; p4[i,j]:=min(p4[i,j],k+min(p4[i+1,j],p4[i,j+1])); end; for i:=1 to m-1 do for j:=i+1 to m do begin //f[z,i,j]:=min(p1[i,j],min(p2[i,j],min(p3[i,j],p4[i,j]))); f[z,i,j]:=p4[i,j]; if p1[i,j]<f[z,i,j] then f[z,i,j]:=p1[i,j]; if p2[i,j]<f[z,i,j] then f[z,i,j]:=p2[i,j]; if p3[i,j]<f[z,i,j] then f[z,i,j]:=p3[i,j]; f[z,i,j]:=f[z,i,j]+a[z,i]+a[z,j]; end; end; ans:=maxlongint; for i:=1 to m do for j:=1 to m do if i<>j then ans:=min(ans,f[n,i,j]); writeln(ans); close(input); close(output); end.
相关文章推荐
- 【GDOI2017第二轮模拟day2】开房间
- jzoj【GDOI2017第二轮模拟day2】开房间
- 【GDOI2017第二轮模拟day2】中位数
- 【JZOJ5065】【GDOI2017第二轮模拟day2】开房间
- 【GDOI2017第二轮模拟day2】中位数
- 【jzoj5065】【GDOI2017第二轮模拟day2】【开房间】【动态规划】
- 【GDOI2017第二轮模拟day1】公路建设
- 【GDOI2017第四轮模拟day2】叶片
- 【GDOI2017第二轮模拟day1】最长路径(性质题,容斥,组合数学)
- 【GDOI2017第二轮模拟day1】最长路径
- 【GDOI2017第三轮模拟day2】树的难题(点剖,树状数组)
- [jzoj5073 GDOI2017第二轮模拟] 影魔
- 【GDOI2017第三轮模拟day2】魔法咒语(AC自动机,矩阵乘法)
- 【JZOJ5066】【GDOI2017第二轮模拟day2】中位数
- GDOI2017第二轮模拟总结
- 【GDOI2017第四轮模拟day2】绝版题
- 【GDOI2017第二轮模拟day1】公路建设(克鲁斯卡尔最小生成树+线段树+归并)
- GDOI2017模拟第二轮 4.15-4.17
- GDOI2017模拟2.16
- 【HNOI模拟By lyp】Day2