JZOJ_1322. 硬币游戏 (Standard IO)

Description

  FJ的奶牛喜欢玩硬币游戏,所以FJ发明了一个新的硬币游戏。一开始有N(5<=N<=2,000)个硬币堆成一叠,从上往下数第i个硬币有一个整数值C_i(1<=C_i<=100,000)。
  两个玩家轮流从上倒下取硬币,玩家1先取,可以从上面取1个或2个硬币,下一轮的玩家可以取的硬币数量最少为1个,最多为上一个玩家取的数量的2倍,硬币全部取完比赛结束。
  已知玩家2绝顶聪明,会采用最优策略,现在请你帮助玩家1,使得玩家1取得的硬币值的和最大。
 

Input

  第一行输入N
  第二至N+1行每行输入一个整数C_i
 

Output

  输出玩家1能获得的最大值。
 

Solution

Fi,j,i表示的是我现在的位置(还剩多少枚硬币),取到第几个,j是对方上一次对方拿走了多少个。

下一次对手就可以取走2*j枚硬币,我们设他要拿走k枚硬币,那么k的取值范围就在1

fi,j=max(sumi+1..k−fk,k−i(1<=k<=2∗j))

fi,j+1=max(sumi+1..k−fk,k−i(1<=k<=2*(j+1)))

J就只有在这个地方发生了改变(手指上方S)

(1<=k<=2∗j) 和 (1<=k<=2*(j+1)) 可以变为 2*j<=k<=2*(j+1)

Fi,j=max(Fi,j−1,Sumi+1..k−Fk,k−i(2∗(j−1)

Fi,j;=max(Fi,j-1,Sumi+1..k-Fk,k-i) (2j+1<=k<=2j+2) (Sum为前缀和)

Maxn;=max(Maxn,Sum[k]-Sum[i]-F[k,k-i])

答案即为 (sum[n]+max(num[1]-f[1,1],num[1]+num[2]-f[2,2])) div 2

因为一开始可以选1或者2

复杂度;O(n2) (2算是常数)

 

代码

 

 1 var
 2   n:longint;
 3   a,sum:array [0..2001] of longint;
 4   f:array [0..2001,0..2001] of longint;
 5 procedure init;
 6 var
 7   i:longint;
 8 begin
 9   readln(n);
10   sum[0]:=0;
11   for i:=1 to n do
12     begin
13       readln(a[i]);
14       sum[i]:=sum[i-1]+a[i];
15     end;
16 end;
17 
18 function min(o,p:longint):longint;
19 begin
20   if o

then exit(o); 21 exit(p); 22 end; 23 24 function max(o,p:longint):longint; 25 begin 26 if o>p then exit(o); 27 exit(p); 28 end; 29 30 procedure main; 31 var 32 i,j,k,maxx:longint; 33 begin 34 for i:=n-1 downto 1 do 35 begin 36 maxx:=-maxlongint; 37 for j:=1 to i do 38 begin 39 for k:=min(i+2*j-2,n)+1 to min(i+2*j,n) do 40 maxx:=max(maxx,sum[k]-sum[i]-f[k,k-i]); 41 f[i,j]:=maxx; 42 end; 43 end; 44 writeln((sum[n]+max(a[1]-f[1,1],a[1]+a[2]-f[2,2])) div 2); 45 end; 46 47 begin 48 init; 49 if n=1 then writeln(a[1]) 50 else main; 51 end.

 

 

 

你可能感兴趣的:(JZOJ_1322. 硬币游戏 (Standard IO))