P7137-[THUPC2021 初赛]切切糕【dp】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P7137


1|1题目大意

有两个人,有n个蛋糕,第i个蛋糕大小为ai

每一次第一个人可以选择一个蛋糕把它切成任意大小的两份(一份可以为空)。

然后第二个人有m次机会优先选择一份拿走,否则都是第一个人先拿。

两个人都希望自己拿走的最多。

求第一个人最终能拿走多少。

1mn2500


1|2解题思路

现在看来还挺简单的,一雪前耻了属于是。

因为是自定义顺序,所以考虑起来比较麻烦所以我们先考虑怎么确定拿的顺序。

瞎猜感性思考一下不难发现,如果我们把大的放在前面,那么第一个人分的时候就分太不平均,因为第二个人手里有选择权威慑,但是如果我们把小的放在前面显然威慑权就到第一个人手里了。因为如果第二个交了太多次机会那么第一个人后面直接全拿,所以此时第二个人不敢交这么多次机会那第一个人就可以全拿了。

所以我们直接敲定是从小到大分,那么顺序固定之后就很简单了,反过来推,设fi,j表示分到第i时还有j次选择权的第一个人总和。
那么我们就有转移方程。

fi,j=max{min{fi1,j1+aix,fi1,j+x}}(x[0,m2])

考虑一下怎么确定这个x,其实也很简单,设A=fi,j,B=fi,j1,那么显然有B>A

如果BAai那么我们直接全拿ai这样第二个人也不会用机会,此时fi,j=B

如果BAai那么我们把ai分给A不足B的那部分后剩下的平分给AB,此时fi,j=B+ai(BA)2

时间复杂度:O(nm)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2510; int n,m; double a[N],f[N][N]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf",&a[i]); sort(a+1,a+1+n); for(int i=n;i>=1;i--){ f[i][0]=f[i+1][0]+a[i]; for(int j=1;j<=m;j++){ double A=f[i+1][j],B=f[i+1][j-1]; //B>A x<=a/2 B+x A+a-x if(B-A<=a[i]) f[i][j]=B+(a[i]-B+A)/2.0; else f[i][j]=A+a[i]; } } printf("%.6lf",f[1][m]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15821579.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-01-19 P5363-[SDOI2019]移动金币【阶梯博弈,dp,组合数学】
2021-01-19 P3306-[SDOI2013]随机数生成器【BSGS】
2021-01-19 P3309-[SDOI2014]向量集【线段树,凸壳】
2021-01-19 P3308-[SDOI2014]LIS【最小割】
2021-01-19 P3313-[SDOI2014]旅行【树链剖分,线段树】
2021-01-19 P4755-Beautiful Pair【笛卡尔树,线段树】
点击右上角即可分享
微信分享提示