CF1987D World is Mine
CF1987D 题解
题意
A 和 B 比赛吃蛋糕,蛋糕共有 \(n\) 个,每一个蛋糕有一个美味值 \(a_i\)。
A 与 B 交替着吃,A 先吃,且 A 需要保证 A 本次吃的蛋糕美味值要严格大于先前 A 所吃的所有蛋糕;接着,B可以吃掉任意一个蛋糕(当然,已经被吃掉的肯定不行),直到有一方无蛋糕可吃为止,游戏结束。
设 \(x\) 为游戏结束时,A 吃下的蛋糕总数。已知 A 和 B 都足够聪明,A 想要最大化 \(x\) 而 B 想要最小化 \(x\),求双方都按自己的最优策略吃蛋糕时,\(x\) 将会是多少。
\(n \le 5000\)
你这 D 怎么比 C 好想这么多.jpg
如果所有蛋糕的美味值两两不同,那么显然 B 做什么复杂的决策是没有意义的,只要 A 不傻就会从最小的蛋糕开始往上递增着吃,B 最多只能吃掉一半的蛋糕,这里就和博弈没什么关系了。所以题目的重点就在于处理那些美味值相同的蛋糕。
对于一批美味值相同的蛋糕,A 想要“拿下”这批蛋糕只需要吃掉其中的一个就可以了,因为吃蛋糕的顺序是严格的单调递增,多出来的那些蛋糕没有意义;而 B 要考虑的就多了需要在 A 吃掉其中任意一个之前把它们全部吃掉。也就是说,假设这批相同美味值的蛋糕有 \(p\) 个,A 让这批蛋糕对 \(x\) 产生一个贡献只需要消耗 \(1\) 回合就行,而 B 要拦截下这个贡献需要 \(p\) 回合。
再结合 A 从小往大吃一定不劣的性质,我们因此可以对 \(a\) 排序、将 \(a\) 相同的蛋糕合并后依次从小往大考虑,对每批美味值相同的蛋糕 \(i\) ,B 可以选择把这个 \(i\) 让给 A 吃来为自己争取到一个空闲回合,用来拦截后面的蛋糕;也可以选择用已经积累好的空闲回合直接出手拦截这个 \(i\),代价就是这批 \(i\) 蛋糕的总个数 \(c_i\)。
基于这个思路做记忆化搜索就好了。设计状态 \(f_{i,j}\) 表示当前考虑到了第 \(i\) 批蛋糕,当前 B 已经攒下了 \(j\) 个空闲回合时已经产生的最小贡献,那么不拦截和拦截产生的转移方程即为 \(f_{i,j}=\min (f_{i+1,j+1}+1,f_{i+1,j-c_i})\),后者需要保证 \(c_i \le j\)。
时空复杂度为 \(O(n^2)\)。
const ll maxn=5005;
ll f[maxn][maxn];
ll a[maxn],tot,b[maxn];
ll n;
ll dfs(ll x,ll t){//记忆化搜索
if(x>tot)return 0;
if(~f[x][t])return f[x][t];
ll res=dfs(x+1,t+1)+1;
if(t>=b[x])res=min(res,dfs(x+1,t-b[x]));
return f[x][t]=res;
}
void solve(){
n=R;
tot=0;
for(ll i=1;i<=n;i++){
a[i]=R;
for(ll j=0;j<=n;j++)f[i][j]=-1;//多测清空
}
sort(a+1,a+1+n);
for(ll i=1;i<=n;i++){
if(a[i]>a[i-1])b[++tot]=1;
else b[tot]++;
}//合并
we(dfs(1,0));
return ;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统