Description:
豆豆和豆沙正在分一些玩具,每个玩具有一个好玩值,每个人可以拿走任意数量的玩具,获得的愉快度为最小的好玩值。现在豆豆先拿,每个人轮流操作,直到没有玩具可以拿。豆豆想知道他能比豆沙多出多少愉快度?
Input:
第一行 N 表示玩具个数。
接下来一行 N 个整数表示第 i 个玩具的好玩值。
Output:
输出一个整数表示最多多出的愉快度。
Sample Input:
3
1 3 1
Sample Output:
2
数据范围:
对于 30% 的数据,N≤10。
对于 70% 的数据,N≤1000。
对于 100 %的数据,N≤1000000,0≤数值范围≤10^9。
出题人的提醒:
1、豆豆和豆沙两位dalao都是绝顶聪明的,不会做出故意让游戏输的行为;
2、愉快度为每轮结算,轮于轮之间累加计算。
题解:
1、通过观察发现,最优情况都是从大到小选的;
2、这是一道DP题,定义 dp[ i ] 表示当前还剩i个物品的最优解;
3、因为对于两个人来说,目的都是使两人愉快度的差值最大,所以上一轮的最优值对于下一轮的先手来说是不好的,所以方程为:
dp[ i ] =max( a[ j + 1] + dp[ j ] ) (0 < j < i )
4、看这个方程 n^2 肯定是不行的,再看一眼,显然单调队列优化,不解释了
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iomanip>
#include<iostream>
#include<cctype>
using namespace std;
int n,a[1000005];
long long max_ans,dp[1000005];
//---------------------
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
//---------------------
int main(){
//freopen("toy.in","r",stdin);
//freopen("toy.out","w",stdout);
n=Readint();
for(int i=1;i<=n;i++) a[i]=Readint();
sort(a+1,a+1+n);
max_ans=a[1];
for(int i=1;i<=n;i++){
dp[i]=max_ans;
max_ans=max((long long)a[i+1]-dp[i],max_ans);
}
cout<<dp[n];
return 0;
}
后记:
这道题,还是应该先确定选玩具的策略,即从大往小选 ,然后再去确定状态和方程,果然 dp 还是做的太少了,还要继续加油。