bzoj 2091 The Minima Game - 动态规划 - 博弈论

题目传送门

  需要验证权限的传送门

题目大意

  Alice和Bob轮流取$n$个正整数,Alice先进行操作。每次每人可以取任意多的数,得分是这一次取的所有数中的最小值。Alice和Bob都足够聪明,他们的策略都是让自己的得分减去对方的得分尽量大。问最终Alice的得分减去Bob的得分。

  因为与顺序无关,所以考虑贪一下心。

  因为使得分劲量大,所以肯定先把大的数取走。

  又因为一次取的得分是所有取的数中的最小值,所以取走的数是排序后的连续的一段。否则对方可以取你间断的那一个数,这样显然不优。

  所以用$f[i]$表示取走前$i$大后,Alice的得分减去Bob的得分,但是这样无法确定转移时谁在操作。

  因此把这个游戏过程倒过来dp,用$f[i]$表示在前$i$小中进行游戏,先手减去后手的得分。

  转移枚举剩下的局面就行了。

  然后这样转移$O(n^{2})$。但是发现dp式子蜜汁雷同:$f[i] = \max_{j = 1}^{i - 1} \{f[j] + a_{j + 1}\}$

  直接记一个东西就可以$O(1)$转移了。

  时间复杂度$O(n\log n)$

Code

 1 /**
 2  * bzoj
 3  * Problem#2091
 4  * Accepted
 5  * Time: 1440ms
 6  * Memory: 13016k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 
16 #define ll long long
17 
18 int n;
19 ll *f;
20 int *ar;
21 
22 inline void init() {
23     scanf("%d", &n);
24     f = new ll[(n + 1)]; 
25     ar = new int[(n + 1)];
26     for (int i = 1; i <= n; i++)
27         scanf("%d", ar + i);
28 } 
29 
30 inline void solve() {
31     sort(ar + 1, ar + n + 1); 
32     f[1] = ar[1];
33     for (int i = 2; i <= n; i++)
34         f[i] = max(f[i - 1], ar[i] - f[i - 1]);
35     printf(Auto"\n", f[n]);
36 }
37 
38 int main() {
39     init();
40     solve();
41     return 0;
42 }
posted @ 2018-03-09 20:08  阿波罗2003  阅读(...)  评论(...编辑  收藏