B4168 [GXPC-S 2024] 分糖果 题解

· · 题解

题意:

n 包糖果从左到右排列,小林和小伊分糖,小林先分配。分配者可以把当前最左的糖分给自己或对方,没拿到糖的人则下一次分配糖。两人会用最优策略让自己的糖的总数尽可能多,最终求两人中糖更多的那个人糖果数量值。

分析:

一眼 dp 不用说,dp 就要考虑要状态定义和状态转移。

状态定义

$dp[1][i]$ 表示分第 $i$ 包糖且**当前为小伊分配**时,小伊能获得的最大糖数。 #### 状态转移 正着想推你会想了很久都不会转移,故考虑从后往前推,易发现第 $i$ 包的决策依赖于第 $i+1$ 包的结果。 每个人都有两种选择: - 把第 $i$ 包糖分给自己:此时自己获得 $a[i]$,分配权转移到另一个人手中,后续能获得 $dp[1][i+1]$,总收益为 $dp[1][i+1] + a[i]$。 - 把第 $i$ 包糖分给另一个人:此时自己收益就为 $0$,但分配权仍在自己手中,后续能获得 $dp[0][i+1]$,总收益为 $dp[0][i+1]$。 因为要选择收益更大的方案,因此得转移方程: $$ dp[0][i] = \max (dp[1][i+1] + a[i], dp[0][i+1]) $$ 另一个人则获得: $$ dp[1][i] = \min(dp[1][i+1] + a[i], dp[0][i+1]) $$ 因为小林先分,所以他总能获得更多的糖(先分糖的人不可能拿的少吧),所以答案直接输出 $dp[0][i]$ 即可 --- ### Code: ```c++14 #include<bits/stdc++.h> #define int long long #define cin std::cin #define cout std::cout #define endl '\n' // 宏定义 using namespace std; const int maxn=1e5+5; int n,a[maxn],dp[2][maxn]; signed main(){ ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0); // 关闭流同步提升 cin/cout 性能 cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; // 读入 for(int i=n;i>=1;i--){ dp[0][i]=max(dp[1][i+1]+a[i],dp[0][i+1]); dp[1][i]=min(dp[1][i+1]+a[i],dp[0][i+1]); } // 转移 cout<<dp[0][1]<<endl; return 0; } ``` --- ### 致谢 感谢 @[StelChord](luogu://user/1115911) 大佬对输出答案代码的优化 管理员大大辛苦了