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;
}
posted @ 2022-01-19 11:27  QuantAsk  阅读(36)  评论(0编辑  收藏  举报