NOIP2007(矩阵取数游戏)

算法:高精度+DP
万恶的高精度啊,伤不起啊伤不起~~~~~~
因为本题是总共取m次,而且是每行都要取m次,而且行与行之间没有必然的联系,因此就可以把它们分开计算,每次算一行的。
说一下DP方程吧:设f[i,j,k]表示第i行取了j个元素在前面取了k个元素的最大值。则f[i,j,k]:=max(f[i,j-1,k-1]+find[j]*a[i,k],f[i,j-1,k]+find[j]*a[i,m-(j-k)+1])即如果第j个从前面选,那么就是从f[i,j-1,k-1]转移而来,同时要加上第k次选的a[i,k]和2的j次方。如果从后面选,就是从f[i,j-1,k]转移而来。再加上从后面选的那个数和2的j次方。

最后就是麻烦的高精度,太恶心了~~~~~~~~~~~~~

program game;

type
	arr=array [0..30] of longint;

var
	ans:arr;
	n,m:longint;
	maxx:array [-1..100] of arr;
	f:array [-1..100,-1..100,-1..100] of arr;
	find:array [-1..100] of arr;
	a:array [-1..100,-1..100] of longint;

function gjc(x:arr; t:longint):arr;{高精度乘法}
var
	i,xx,len:longint;
begin
	fillchar(gjc,sizeof(gjc),0);
	xx:=0;
	len:=x[0];
	for i:=1 to x[0] do
		begin
			xx:=x[i]*t;
			gjc[i+1]:=xx div 10000;
			gjc[i]:=xx mod 10000+gjc[i];
		end;
	while (gjc[len]=0) and (len>1) do dec(len);
	if gjc[x[0]+1]<>0 then gjc[0]:=x[0]+1 else gjc[0]:=x[0];
end;

procedure jsjc;{计算2的n次方}
var
	i:longint;
begin
	fillchar(find,sizeof(find),0);
	find[0,0]:=1;
	find[0,1]:=1;
	for i:=1 to m do find[i]:=gjc(find[i-1],2);			
end;
	
function gjj(x:arr; y:arr):arr;{高精度加法}
var
	i,len:longint;
begin
	fillchar(gjj,sizeof(gjj),0);
	len:=0;
	if x[0]>=y[0] then len:=x[0] else len:=y[0];
	for i:=1 to len do 
		begin
			gjj[i]:=x[i]+y[i]+gjj[i];
			gjj[i+1]:=gjj[i] div 10000;
			gjj[i]:=gjj[i] mod 10000;
		end;
	if gjj[len+1]<>0 then gjj[0]:=len+1 else gjj[0]:=len;
end;
	
function max(x:arr; y:arr):arr;{判断,比大小过程}
var
	i:longint;
begin
	fillchar(max,sizeof(max),0);
	if x[0]>y[0] then exit(x);
	if x[0]<y[0] then exit(y);
	for i:=x[0] downto 1 do if x[i]>y[i] then exit(x) else if y[i]>x[i] then exit(y);
	exit(x);
end;
	
procedure init;
var
	i,j:longint;
begin
	readln(n,m);
	for i:=1 to n do
		begin
			for j:=1 to m do read(a[i,j]);
			readln;
		end;
	jsjc;
end;
			
procedure main;
var
	i,j,k:longint;
begin
	fillchar(f,sizeof(f),0);
	fillchar(maxx,sizeof(maxx),0);
	for i:=1 to n do
		begin
			for j:=1 to m do
				begin
					for k:=0 to j do 
						begin
							f[i,j,k]:=max(gjj(f[i,j-1,k-1],gjc(find[j],a[i,k])),gjj(f[i,j-1,k],gjc(find[j],a[i,m-(j-k)+1])));
						end;
				end;
			for j:=0 to m do maxx[i]:=max(maxx[i],f[i,m,j]);
		end;
end;
				
procedure outit;
var
	i:longint;
begin
	for i:=1 to n do ans:=gjj(ans,maxx[i]);{累加过程}
end;
	
procedure print;
var
	i:longint;
begin
	for i:=ans[0] downto 1 do 
		begin
			if i<>ans[0] then{别忘了打印0的情况}
				begin
					if ans[i]<1000 then write(0);
					if ans[i]<100 then write(0);
					if ans[i]<10 then write(0);
				end;
			write(ans[i]);
		end;
end;	

begin
	assign(input,'game.in'); reset(input);
	assign(output,'game.out'); rewrite(output);

	init;
	main;
	outit;
	print;

	close(input); close(output);
end.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值