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<k<=2∗j。

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)<k<=2∗j))

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<p 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.

猜你喜欢

转载自www.cnblogs.com/zyx-crying/p/9489350.html
今日推荐