KK's Number

问题描述:
    我们可爱的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
输出样例
2
Hint
首先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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值