NOIP模拟 分玩具【博弈论】【动态规划】

本文介绍了一个关于玩具分配的游戏问题,通过动态规划求解两人轮流选择玩具时如何最大化愉快度之差。文章提供了完整的代码实现,并解释了解题思路及优化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

豆豆和豆沙正在分一些玩具,每个玩具有一个好玩值,每个人可以拿走任意数量的玩具,获得的愉快度为最小的好玩值。现在豆豆先拿,每个人轮流操作,直到没有玩具可以拿。两人都按最优策略选玩具,豆豆想知道他能比豆沙多出多少愉快度?

输入格式

第一行 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]),ijn。复杂度为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;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值