题目描述
豆豆和豆沙正在分一些玩具,每个玩具有一个好玩值,每个人可以拿走任意数量的玩具,获得的愉快度为最小的好玩值。现在豆豆先拿,每个人轮流操作,直到没有玩具可以拿。两人都按最优策略选玩具,豆豆想知道他能比豆沙多出多少愉快度?
输入格式
第一行 N 表示玩具个数。
接下来一行 N 个整数表示第 i 个玩具的好玩值。
输出格式
输出一个整数表示最多多出的愉快度。
样例数据 1
输入 [复制]
3
1 3 1
输出
2
备注
【数据范围】
对于 30% 的数据,N≤10。
对于 70% 的数据,N≤1000。
对于 100 %的数据,N≤1000000,0≤数值范围≤1e9。
解题思路:
先将数组从大到小排序。
若一个人选了玩具1~i最优,则它的愉悦值为a[i];
轮到另一个人选,由于他也按最优策略选,所以是个完全相同的子问题。
假设玩具1~i-1已被选;
我们设dp[i]表示A从i开始先手选玩具可得到的最大差,设他选到了玩具j,那么他获得了a[j]的愉悦值,现在就轮到B从j+1开始选,那他可获得的最大差为dp[j+1],所以A的愉悦值将会比B多a[j]-dp[j+1]。
得到dp方程:dp[i]=max(a[j]-dp[j+1]),i≤j≤n。复杂度为O(n2);
而我们是从n到1进行dp,就可以维护a[j]-a[j+1]的最大值,从而使复杂度降至O(n)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=1e6+5;
int n,mx,a[N],dp[N];
bool cmp(const int &a,const int &b)
{
return a>b;
}
int main()
{
//freopen("toy.in","r",stdin);
//freopen("toy.out","w",stdout);
n=getint();
for(int i=1;i<=n;i++)a[i]=getint();
sort(a+1,a+n+1,cmp);
for(int i=n;i>=1;i--)
dp[i]=mx=max(mx,a[i]-dp[i+1]);
cout<<dp[1];
return 0;
}