【区间DP】 UVA10891 Game of Sum

这题贪心的话似乎不太可行我没想出怎么贪,所以用区间dp来解决。

更好的阅读体验:qwq

分析

f[l][r] 表示先手在区间 [l,r] 的最优决策所能给他带来的贡献,因为区间 [l,r] 的总和 s[l,r] 是一定的,那么这个最优决策在意味着最大化自己的收益同时也表示最小化对手的收益。

对于 [l,r] 的先手,他有三种策略:

  • 从左开始取走一定的数,最小化对手剩下的收益。
  • 从右开始取走一定的数,最小化对手剩下的收益。
  • 取走所有数,对手收益为 0

据此,可以写出状态转移方程:
f[l][r]=s[l][r]min{0,mink=l+1rf[k][r],mink=lr1f[l][k]}

直接递推复杂度为 O(N3) ,可以考虑优化:
g[l][r]=mink=lrf[k][r]h[l][r]=mink=lrf[l][k]

根据 g[l][r] 的规律,我们有 g[l][r]=min(f[l][r],mink=l+1rf[k][r])

类似地,h[l][r]=min(f[l][r],mink=lr1f[l][k])

这样我们就可以在更新完 f[l][r] 后一起更新 g[l][r],h[l][r] ,使得复杂度降为 O(N2)

#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define rep(i,a,b) for(int i=(a);i<=(b);i++)

inline void read(int &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=105;
int n, w[N], s[N];
int f[N][N], g[N][N], h[N][N];

int main(){
	while(cin>>n, n){
		rep(i,1,n) read(w[i]), s[i]=s[i-1]+w[i];
		
		rep(i,1,n) f[i][i]=g[i][i]=h[i][i]=w[i];
		rep(len,2,n) rep(l,1,n){
			int r=l+len-1;
			f[l][r]=s[r]-s[l-1]-min(0, min(g[l+1][r], h[l][r-1]));
			
			g[l][r]=min(f[l][r], g[l+1][r]), h[l][r]=min(f[l][r], h[l][r-1]);
		}
		cout<<f[1][n]-(s[n]-f[1][n])<<endl;
	}
    return 0;
}
posted @   HinanawiTenshi  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示