【DP优化】【P1430】序列取数

传送门

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%的数据,n1000,T100

Solution

显然是博弈DP。考虑设fi,j是区间[i,j]先手取数的最大答案。转移显然为
fi,j=sumjsumiminfk,j,fi,k,其中满足i < k < j。枚举k进行转移,复杂度是O(n3)。直接凉凉。
状态已经是O(n2)无法优化。考虑对转移进行优化。考虑枚举k是求一定区间内f的最大值。这个f的区间是从小到大枚举的,所以可以维护区间内f的最大值。具体的,设li,j代表maxfi,kri,j代表maxfk,r,其中满足i < k < j
这样转移方程就变成fi,j=sumjsumiminli,j,ri,j。这样使用DP对DP进行优化,转移变成O(1)的,可以通过本题。
其中li,j=maxli,j1,fi,jr的转移同理。

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进行优化。

posted @   一扶苏一  阅读(332)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示