传送门

Description

给定一个长为n的整数序列,由A和B轮流取数(A先取)。每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取。所有数都被取走后,两人分别统计所取数的和作为各自的得分。假设A和B都足够聪明,都使自己得分尽量高,求A的最终得分。

Input

第一行,一个正整数T,表示有T组数据。

接着T行,每行第一个数为n,接着n个整数表示给定的序列.

Output

输出T行,每行一个整数,表示A的得分

Sample Input

2
1 -1
2 1 2

Sample Output

-1
3

Hint

时限3s。

对于100%的数据,\(n \leq 1000, T \leq 100\)

Solution

显然是博弈DP。考虑设\(f_{i,j}\)是区间\([i,j]\)先手取数的最大答案。转移显然为

\(f_{i,j}=sum_j-sum_i-min{f_{k,j},f_{i,k}}\),其中满足\(i~<~k~<~j\)。枚举\(k\)进行转移,复杂度是\(O(n^3)\)。直接凉凉。

状态已经是\(O(n^2)\)无法优化。考虑对转移进行优化。考虑枚举\(k\)是求一定区间内\(f\)的最大值。这个\(f\)的区间是从小到大枚举的,所以可以维护区间内\(f\)的最大值。具体的,设\(l_{i,j}\)代表\(max{f_{i,k}}\),\(r_{i,j}\)代表\(max{f_{k,r}}\),其中满足\(i~<~k~<~j\)。

这样转移方程就变成\(f_{i,j}=sum_j-sum_i-min{l_{i,j},r_{i,j}}\)。这样使用DP对DP进行优化,转移变成\(O(1)\)的,可以通过本题。

其中\(l_{i,j}=max{l_{i,j-1},f_{i,j}}\),\(r\)的转移同理。

Code

#include<cstdio>
#include<cstring>
#define rg register
#define ci const int
#define cl const long long int typedef long long int ll; namespace IO {
char buf[50];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if (lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) {putchar('-');x=-x;}
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template <typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;} template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} const int maxn = 1010; int t,n;
int MU[maxn],frog[maxn][maxn],lmax[maxn][maxn],rmax[maxn][maxn],sum[maxn]; void clear(); int main() {
qr(t);
while(t--) {
clear() ;
qr(n);
for(rg int i=1;i<=n;++i) qr(MU[i]);
for(rg int i=1;i<=n;++i) lmax[i][i]=rmax[i][i]=frog[i][i]=MU[i],sum[i]=sum[i-1]+MU[i];
for(rg int i=1;i<n;++i) {
for(rg int j=1;j<n;++j) {
rg int r=i+j;if(r>n) break;
frog[j][r]=sum[r]-sum[j-1]-mmin(0,mmin(lmax[j][r-1],rmax[j+1][r]));
lmax[j][r]=mmin(frog[j][r],lmax[j][r-1]);rmax[j][r]=mmin(frog[j][r],rmax[j+1][r]);
}
}
write(frog[1][n],'\n',true);
}
return 0;
} void clear() {
memset(MU,0,sizeof MU);
memset(sum,0,sizeof sum);
memset(frog,0,sizeof frog);
memset(lmax,0,sizeof lmax);
memset(rmax,0,sizeof rmax);
n=0;
}

Summary

在DP因为复杂度较高而无法承受时,考虑对转移进行优化。常见的如维护区间最大/最小值,通过数据结构或者DP进行优化。

【DP优化】【P1430】序列取数的更多相关文章

  1. 洛谷 P1430 序列取数 解题报告

    P1430 序列取数 题目描述 给定一个长为\(n\)的整数序列\((n<=1000)\),由\(A\)和\(B\)轮流取数(\(A\)先取).每个人可从序列的左端或右端取若干个数(至少一个), ...

  2. 洛谷 P1430 序列取数

    如果按照http://www.cnblogs.com/hehe54321/p/loj-1031.html的$O(n^3)$做法去做的话是会T掉的,但是实际上那个做法有优化的空间. 所有操作可以分解为由 ...

  3. 【Luogu】P1430序列取数(DP)

    题目链接 博弈DP太喵了qwq 设f[i][j]表示剩下区间[i,j]要取,先手最大值 明显我们要从这区间里面拿个最大的 就等价于这段区间的前缀和,我们要给对手留下个最小的 就是f[i][j]=sum ...

  4. [洛谷P1430]序列取数

    题目大意:给定一个序列$s$,每个人每轮可以从两端(任选一端)取任意个数的整数,不能不取.在两个人都足够聪明的情况下,求先手的最大得分. 题解:设$f_{i,j}$表示剩下$[i,j]$,先手的最大得 ...

  5. 「LuoguP1430」 序列取数(区间dp

    题目描述 给定一个长为n的整数序列(n<=1000),由A和B轮流取数(A先取).每个人可从序列的左端或右端取若干个数(至少一个),但不能两端都取.所有数都被取走后,两人分别统计所取数的和作为各 ...

  6. HDU 1565&1569 方格取数系列(状压DP或者最大流)

    方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  7. HDU3045 Picnic Cows (斜率DP优化)(数形结合)

    转自PomeCat: "DP的斜率优化--对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能.斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映 ...

  8. 洛谷 P1004 方格取数 【多进程dp】

    题目链接:https://www.luogu.org/problemnew/show/P1004 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 ...

  9. 51Nod 1084:矩阵取数问题 V2(多维DP)

    1084 矩阵取数问题 V2  基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励 ...

随机推荐

  1. Java 递归 反射 正则表达式

    一 递归 1. 就是函数自身调用自身 (就是在栈内存中不断的加载同一个函数) 2. 什么时候用递归呢? 当一个功能被重复使用 而每一次使用该功能时的参数不确定 都由上次的功能元素结果来确定 简单说: ...

  2. Java开发工程师(Web方向) - 01.Java Web开发入门 - 第4章.Maven

    第4章--Maven Maven实战 Java Web应用的部署: 手动式: 编译:javac -cp $CATALINA_HOME/lib/servlet-api.jar web-inf/class ...

  3. 【system.file】使用说明

    对象:system.file 说明:提供一系列针对文件操作的方法. 注意:参数中的filePath 均为相对网站根目录路径 目录: 方法 返回 说明 system.file.exists(filePa ...

  4. spring入门(Ioc的理解)

    spring对依赖的注入理解可以参考这篇:https://www.cnblogs.com/alltime/p/6729295.html 依赖注入和控制反转 传统的JavaEE程序中,直接在内部new一 ...

  5. OpenMPI源码剖析4:rte.h 头文件的说明信息

    上一篇文章中说道,我们在 rte.h 中发现了有价值的说明: 我们一块一块来分析,首先看到第一块,关于 Process name Object: * (a) Process name objects ...

  6. 如何借助windows的VHD引导特性实现VHD多windows系统共存

    近期,由于一些需要,需要运行3个windows系统,具体需要如何此处略去,现将实现方式共享如下. 测试环境: HP 820 G2, 4G内存, 500G SSD硬盘 windows 7 企业版 win ...

  7. POJ 2069 Super Star(计算几何の最小球包含+模拟退火)

    Description During a voyage of the starship Hakodate-maru (see Problem 1406), researchers found stra ...

  8. JS中Document节点总结

    document对象是documentHTML的一个实例,也是window对象的一个属性,因此可以将document对象作为一个全局对象来访问. Document节点的子节点可以是DocumentTy ...

  9. 图的遍历——DFS(邻接矩阵)

    递归 + 标记 一个连通图只要DFS一次,即可打印所有的点. #include <iostream> #include <cstdio> #include <cstdli ...

  10. iOS开发解决页面滑动返回跟scrollView左右划冲突

    -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithG ...