洛谷 U1406 game

題目描述 Description
給出n個正整數,Archon、wxjlzbcd兩個人輪流取任意數量的數,遊戲的結束條件是n個數都被取走。
每次取數時,獲得的得分爲所取數中的最小值。
假設Archon先取數,Archon和wxjlzbcd的策略都是儘可能使得自己的得分減去對手的得分更大,請求出遊戲結束時Archon的得分減去wxjlzbcd的得分爲多少。
輸入輸出格式 Input/output
輸入格式:
輸入第1行爲一個整數n,表示整數個數。
輸入第2行爲給出的n個整數a_i。
輸出格式:
輸出第1行爲一個整數ans,表示Archon的得分減去wxjlzbcd的得分。
輸入輸出樣例 Sample input/output
樣例測試點#1 輸入樣例:
3
1 3 1
輸出樣例:
2
說明 description
對於樣例,Archon取走第二個數,wxjlzbcd取走第一個和第三個數。答案爲3-1=2。
對於30%的數據,1≤n≤10;
對於100%的數據,1≤n≤1000000,1≤a_i≤10^9。

這個題真是神!~
╮(╯▽╰)╭平時這種題練得少。。。。一道DP。。啊啊啊啊。。DP主要在理解。。。很拼智力

現在用f[i]表示剩餘有i個數時 先手-後手 的最大差值(題意使然),那麼答案就是f【n】(下面會詳細解釋)
用a數組記錄讀入的數字
先qsort a數組使其單增,作用後續可知
現在推證狀態轉移方程:(注意題目中要求“每次取數時,獲得的得分爲所取數中的最小值”,差值最大不一定是取最大值,)

f【i】:=max(num[i]-f[i],f[i-1]) (for i:=1 to n)

遞推就是取數過程的倒推模擬

* 此方程的效應等同於 A每次取得的得分和(即A的總得分)-B每次取得的得分和(即B的總得分)*

此方程展開:
現在用num【i】表示A每次的得分,num【j】表示B每次的得分
f【n】:
=num【i1】-f【n-1】
=num【i1】-(num【j2】-f【n-2】)
=num【i1】-(num【j2】-num【i2】+f【n-3】)
=num【i1】-num【j2】+num【i2】-f【n-3】
=num【i1】+num【i2】-num【j2】-f【n-3】
可知完全展開後即“此方程的效應等同於 A每次取得的得分和(即A的總得分)-B每次取得的得分和(即B的總得分)”
初始狀態f【0】:=0( 顯然)

推證到這裏就應該懂得了當前的最大差值,就等於當前選的數字a【i】減去後手將要獲得的最大差值f【i-1】,這也是此方程進行轉移的基礎和核心

一個人要使自己本次的得分爲num【i】(即取得的所有數中的min爲num【i】),那麼必須取得num【i】及其比它大的所有數,因爲要保證本次自己和另一個人差值最大,所以把比它大的數全部取走,不能留給後手使其縮短差距。所以要qsort使數字遞增,因爲遞推的時候是越往後應使其選擇的數字越大,i越大是剩的數字越多,也就是越靠近最初始的狀態。這個遞推就是取數過程的倒推模擬

 現在結合代碼片說明qsort作用:
   枚舉的時候是a【i】遞增順序,因爲要儘可能使先取的數字大,所以i越大,應使f【i】時選擇的數字越大。枚舉到a【i】的意思是選擇a【i】及其後面的所有數字。
  for i:=1 to n do
    begin
      f[i]:=max(a[i]-f[i-1],f[i-1]);
    end;

思路有點凌亂,但是附上蒟蒻代碼~~~

var maxmax,n,i:longint;
    f,a:array[0..1000000]of longint;

function max(a,b:longint):longint;
begin
  if a>b then exit(a);exit(b);
end;

procedure qsort(b,e:longint);
var l,r,m,t:longint;
begin
  l:=b;r:=e;m:=a[(l+r)>>1];
  while l<=r do
    begin
      while a[l]<m do inc(l);
      while m<a[r] do dec(r);
      if l<=r then
        begin
          t:=a[l];
          a[l]:=a[r];
          a[r]:=t;
          inc(l);
          dec(r);
        end;
    end;
  if l<e then qsort(l,e);
  if b<r then qsort(b,r);
end;

begin
  readln(n);
  for i:=1 to n do read(a[i]);
  qsort(1,n);
  f[0]:=0;
  for i:=1 to n do
    begin
      f[i]:=max(a[i]-f[i-1],f[i-1]);
    end;
  write(f[n]);

end.

 評測結果 Result
測試點 #1:通過該測試點。 得分10,耗時0ms,內存3137kB。
測試點 #2:通過該測試點。 得分10,耗時15ms,內存3145kB。
測試點 #3:通過該測試點。 得分10,耗時15ms,內存3133kB。
測試點 #4:通過該測試點。 得分10,耗時0ms,內存3112kB。
測試點 #5:通過該測試點。 得分10,耗時0ms,內存3174kB。
測試點 #6:通過該測試點。 得分10,耗時46ms,內存3936kB。
測試點 #7:通過該測試點。 得分10,耗時62ms,內存4845kB。
測試點 #8:通過該測試點。 得分10,耗時358ms,內存11141kB。
測試點 #9:通過該測試點。 得分10,耗時390ms,內存11124kB。
測試點 #10:通過該測試點。 得分10,耗時514ms,內存11116kB。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章