问题描述: 我们可爱的KK有一个有趣的数学游戏: 这个游戏需要两个人,有N(1≤N≤5∗104)个数,每次KK都会先拿数。 每次可以拿任意多个数,直到NN个数被拿完。每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大。 在这样的情况下,最终KK的得分减去对手的得分会是多少?输入描述第一行一个数T(1≤T≤10),表示数据组数。 对于每组数据包含两行,第一行一个整数N(1≤N≤5∗104),表示个数,第二行N个正整数(不超过109)。输出描述对于每一个数据输出一个整数,表示最终KK的得分减去对手的得分。输入样例1 3 1 3 1输出样例2Hint首先KK取走3,然后对手取走两个1,那么最终分差为2。
显然是一道博弈dp的题目。
我们要是取数的话肯定是去最后面的大数,留一些小数给对手,所以我们首先显然要排序,取数的时候取a[i]必然把他后面的数一起取走了。假设dp[i] = max(先手得分 - 后手得分)//注:此时只剩下i个数,并且这i个数是从小到大排序的.
假设我们拿的数是(0 < j < i) a[j + 1] (a[j + 1]后面的大数也必然被我们取走了) 此时我们的得分为a[j + 1] - dp[j].
也许可能开始会产生疑问,先手得分是a[j + 1]没错,为何后手就变成了dp[j]呢?
这是因为你取走了a[j + 1],此时对方变成了先手,他也是选择的最优博弈(j + 1后数字全被取走了从前j个数中找到max(先手得分 - 后手得分)).
因此我们可以得到 dp[i] = max(a[j + 1] - dp[j]) (0 <= j < i ).
这样显然还是会超时的,我们发现对于dp[i]和dp[i + 1]每次都比较j 从 0 到 i - 1这一段。
dp[i + 1] = max(dp[i], a[i + 1] - dp[i]);
简单点说就是要么取a[j + 1]的话u,要么还是从前i个数中取
dp[0] = a[0](边界自己注意就好啦),附一份AC代码。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define FOR(i, x, y) for(int i = x; i <= y; i ++)
#define FORD(i, y, x) for(int i = y; i >= x; i --)
#define mset(x, v) memset(x, v, sizeof(x))
#define maxn 50055
#define ll long long
typedef unsigned long long ull;
using namespace std;
int a[maxn], dp[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t;
cin >> t;
while(t--){
int n;
scanf("%d", &n);
FOR(i, 0, n - 1){
scanf("%d", &a[i]);
}
sort(a, a + n);
dp[0] = a[0];
FOR(i, 1, n - 1){
dp[i] = dp[i - 1];
dp[i] = max(dp[i], a[i] - dp[i - 1]);
// cout << i << " aa " << dp[i] <<endl;
}
printf("%d\n", dp[n - 1]);
}
return 0;
}