| | | | 背景 Background | | | NOIP2007年提高组第三道 | | | |
| | | | 描述 Description | | | 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素; 2. 每次取走的各个元素只能是该元素所在行的行首或行尾; 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号); 4. 游戏结束总得分为m次取数得分之和。 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。 | | | |
| | | | 输入格式 Input Format | | | 输入文件game.in包括n+1行: 第1行为两个用空格隔开的整数n和m。 第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。 | | | |
| | | | 输出格式 Output Format | | | 输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。 | | | |
| | | | 样例输出 Sample Output [复制数据] | | | | | | |
| | | | 时间限制 Time Limitation | | | 各个测试点1s 由于服务器配置原因,不得不修改部分测试点的时间限制,请大家使用高精度并且压8位,否则过不了! | | | |
| | | | 注释 Hint | | | 【输入输出样例1解释】 第1次:第1行取行首元素,第2行取行尾元素,本次得分为1*2^1+2*2^1=6 第2次:两行均取行首元素,本次得分为2*2^2+3*2^2=20 第3次:得分为3*2^3+4*2^3=56。总得分为6+20+56=82 【限制】 60%的数据满足:1<=n, m<=30, 答案不超过10^16 100%的数据满足:1<=n, m<=80, 0<=aij<=1000 | 由于各行是独立的,所以可以分开来计算. f[i,j]表示前i次取数左边取了j次的最大得分。 决策就是第i次是取左边的数或者取右边的数。 p[i]表示2^i。 f[i,j]:=max(f[i-1,j-1]+a[j]*p[i],f[i-1,j]+a[m-i+j+1]*p[i]); 由于a[i]最大可以达到1000,而m最大为80。 显然我们要用高精度运算来计算f[i,j] 这种方程写法必须用高精度乘法与加法。 若换一种写法则只需用高精加法,大家可以自行google。代码很长。。。。顺带复习了一下高精度乘法压4位。 type rr=array[1..1000]of longint;
var i,j,k,n,m,ans,s:longint;
f:array[0..80,-1..80]of ansistring;
p,ak:array[1..80]of ansistring;
a:array[1..80]of longint;
a1,b1,c1: rr;
tot:ansistring;
procedure work(a:ansistring; var c:rr);
var i,j,s:longint;
st:ansistring;
begin
i:=length(a);
if i mod 4 =0 then s:=i div 4 else s:=i div 4+1 ;
while i>=4 do
begin
st:=copy(a,i-3,4);
val(st,c[s]);
i:=i-4;
s:=s-1;
end;
if i>0 then begin
st:=copy(a,1,i);
val(st,c[1]);
end;
end;
procedure insert(var cc:ansistring;p:longint);
var ss:ansistring;
begin
str(p,ss);
cc:=cc+ss;
end;
function multi(a,b:ansistring):ansistring;
var len1,len2,i,j,s1,s2:longint;
flag:boolean;
cc,pp:ansistring;
begin
fillchar(c1,sizeof(c1),0);
fillchar(a1,sizeof(a1),0);
fillchar(b1,sizeof(b1),0);
len1:=length(a);len2:=length(b);
if len1 mod 4 =0 then len1:=len1 div 4 else len1:=len1 div 4 +1;
if len2 mod 4 =0 then len2:=len2 div 4 else len2:=len2 div 4 +1;
work(a,a1);work(b,b1);
for i:=len1 downto 1 do
for j:=len2 downto 1 do
begin
c1[i+j-1]:=c1[i+j-1]+a1[i]*b1[j];
c1[i+j-2]:=c1[i+j-2]+(c1[i+j-1] div 10000);
c1[i+j-1]:=c1[i+j-1] mod 10000;
end;
cc:='';
if c1[0]<>0 then insert(cc,c1[0]);
if c1[0]=0 then insert(cc,c1[1]) else begin
if c1[1]<10 then cc:=cc+'000'
else if c1[1]<100 then cc:=cc+'00'
else if c1[1]<1000 then cc:=cc+'0';
insert(cc,c1[1]); end;
for i:=2 to len1+len2-1 do
begin
if c1[i]<10 then cc:=cc+'000'
else if c1[i]<100 then cc:=cc+'00'
else if c1[i]<1000 then cc:=cc+'0';
insert(cc,c1[i]);
end;
exit(cc);
end;
function add(a,b:ansistring):ansistring;
var i,j,len1,len2:longint;
a1,b1,c1:array[0..1000]of longint;
c:ansistring;
begin
fillchar(a1,sizeof(a1),0);
fillchar(b1,sizeof(b1),0);
fillchar(c1,sizeof(c1),0);
len1:=length(a);len2:=length(b);
while len1<len2 do
begin
a:='0'+a;
inc(len1);
end;
while len2<len1 do
begin
b:='0'+b;
inc(len2);
end;
for i:=1 to len1 do a1[i]:=ord(a[i])-48;
for i:=1 to len2 do b1[i]:=ord(b[i])-48;
for i:=len1 downto 1 do
begin
c1[i-1]:=(c1[i]+a1[i]+b1[i])div 10;
c1[i]:=(c1[i]+a1[i]+b1[i])mod 10;
end;
c:='';
if c1[0]<>0 then c:=c+chr(c1[0]+48);
for i:=1 to len1 do c:=c+chr(c1[i]+48);
exit(c);
end;
procedure init;
var i:longint;
kk:ansistring;
begin
kk:='1';
for i:=1 to m do
begin
kk:=multi(kk,'2');
p[i]:=kk;
end;
end;
function max(a,b:ansistring):ansistring;
var i:longint;
begin
if length(a)>length(b) then exit(a);
if length(a)=length(b) then
begin
for i:=1 to length(a) do
begin
if a[i]>b[i] then exit(a);
if a[i]<b[i] then exit(b);
end;
end;
exit(b);
end;
procedure dp;
var i,j:longint;
max1:ansistring;
begin
max1:='0';
fillchar(f,sizeof(f),0);
for i:=1 to m do
for j:=0 to i do
f[i,j]:=max(add(f[i-1,j-1],multi(ak[j],p[i])),add(f[i-1,j],multi(ak[m-i+j+1],p[i])));
for i:=0 to m do
max1:=max(max1,f[m,i]);
tot:=add(max1,tot);
end;
begin
readln(n,m);tot:='0';init;
for k:=1 to n do
begin
for j:=1 to m do
begin
read(a[j]);
str(a[j],ak[j]);
end;
dp;
readln;
end;
writeln(tot);
end. |