【DP】[Dota1001]地精工程师(GoblinTech)
描述
地精工程师的主要工作就是埋炸弹……
在一个M*N的矩形土地上,会有许多的小兵侵入,这些小兵都是钱啊,地精工程师怎能放弃这个刷钱的机会?于是,地精工程师决定埋一个遥控炸弹,等小兵都站好再引爆。
地精工程师的炸弹可以轰掉一个矩形区域,并收到所有这个矩形区域中小兵的钱。
有的小兵是魔法师……炸掉这个小兵可以让得到的钱乘2,如果炸掉多个这样的小兵,得到的钱就是原来的2^x倍(x为炸掉魔法师的个数)
地精工程师想知道,他最多能得到多少钱?输入
第一行,两个数M,N
接下来M行N列的矩阵,表示炸掉每个位置上的小兵的钱
接下来一个数T
接下来T行,每行两个数x,y,表示位于x,y的小兵是魔法师输出
一个数,表示最多得到多少钱
样例输入
3 3 -1 -1 1 1 -1 1 1 1 1 1 1 3样例输出
6
提示
M,N<=100
T<=10
矩阵中的数在[-500,500]之间
【Solution】
这是一个最优子矩阵的变形,其中的矩阵价值是可变的,所以我们需要在原来的方程上多加一维。
(Zip后)F[i,j]表示前i个数中已经选了j个魔法兵所获得的最大金钱。B[i]存储每个格子的魔法兵数目。
F[i,j]←max{((F[i-1,j-b[i]]/2j-b[i])+a[i])*2j,a[i]*2b[i]}
【Code】
1: Program GoblinTech(input,output);2: var F:array[0..100,-10..10]of int64;3: a:array[1..100,1..100]of longint;4: Magic:array[1..100,1..100]of boolean;5: aa,b,bb:array[0..100]of longint;6: up,down,i,t,j,n,m,x,y:longint;7: ans:int64;8: Function max(a,b:Longint):longint;9: begin
10: if a>b then exit(a) else exit(b);11: end;
12: Procedure zip(up,down:longint);13: var i,j:longint;
14: begin
15: fillchar(aa,sizeof(aa),0);16: fillchar(b,sizeof(b),0);17: for i:=1 to m do18: begin
19: bb[i]:=bb[i-1];20: for j:=up to down do21: begin
22: inc(aa[i],a[j,i]);23: if Magic[j,i] then begin inc(b[i]);inc(bb[i]);end;24: end;
25: end;
26: end;
27: begin
28: readln(n,m);29: for i:=1 to n do30: for j:=1 to m do31: read(a[i,j]);32: readln(t);fillchar(Magic,sizeof(Magic),false);33: for i:=1 to t do begin readln(x,y);Magic[x,y]:=true;end;34: ans:=-5120000000;35: for up:=1 to n do36: for down:=1 to n do37: begin
38: Zip(up,down);39: fillchar(F,sizeof(F),0);40: for i:=1 to m do41: for j:=b[i] to bb[i] do42: begin
43: F[i,j]:=max(((F[i-1,j-b[i]] div (1<<(j-b[i])))+aa[i])*(1<<j),
44: aa[i]*(1<<b[i]));45: if F[i,j]>ans then ans:=F[i,j];46: end;
47: end;
48: writeln(ans);49: end.