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


    正题

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


    题目大意

    有两个人,有\(n\)个蛋糕,第\(i\)个蛋糕大小为\(a_i\)

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

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

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

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

    \(1\leq m\leq n\leq 2500\)


    解题思路

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

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

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

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

    \[f_{i,j}=max\{min\{f_{i-1,j-1}+a_i-x,f_{i-1,j}+x\}\}(x\in[0,\frac{m}{2}]) \]

    考虑一下怎么确定这个\(x\),其实也很简单,设\(A=f_{i,j},B=f_{i,j-1}\),那么显然有\(B>A\)

    如果\(B-A\geq a_i\)那么我们直接全拿\(a_i\)这样第二个人也不会用机会,此时\(f_{i,j}=B\)

    如果\(B-A\leq a_i\)那么我们把\(a_i\)分给\(A\)不足\(B\)的那部分后剩下的平分给\(A\)\(B\),此时\(f_{i,j}=B+\frac{a_i-(B-A)}{2}\)

    时间复杂度:\(O(nm)\)


    code

    #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;
    }
    
  • 相关阅读:
    java 大数据比较两个list集合的差值
    service手动回滚
    mycat分库分表demo
    mysql集群搭建之读写分离
    Python 代码运行速度慢?用PyPy模块让你的速度起飞!
    大新闻!Python 之父重新出山,加入微软开发部
    附实战代码|告别OS模块,体验Python文件操作新姿势!
    Python九个最佳IDE集成开发环境,你用过吗?
    五个阶段让你成为Python专家,你确定不看看吗?
    制作交互式数据可视化图表,只需要一个Python库就能实现!
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15821579.html
Copyright © 2020-2023  润新知