【DP优化】【P1430】序列取数
傳送門
Description
給定一個長為n的整數(shù)序列,由A和B輪流取數(shù)(A先取)。每個人可從序列的左端或右端取若干個數(shù)(至少一個),但不能兩端都取。所有數(shù)都被取走后,兩人分別統(tǒng)計所取數(shù)的和作為各自的得分。假設(shè)A和B都足夠聰明,都使自己得分盡量高,求A的最終得分。
Input
第一行,一個正整數(shù)T,表示有T組數(shù)據(jù)。
接著T行,每行第一個數(shù)為n,接著n個整數(shù)表示給定的序列.
Output
輸出T行,每行一個整數(shù),表示A的得分
Sample Input
2 1 -1 2 1 2Sample Output
-1 3Hint
時限3s。
對于100%的數(shù)據(jù),\(n \leq 1000, T \leq 100\)
Solution
顯然是博弈DP。考慮設(shè)\(f_{i,j}\)是區(qū)間\([i,j]\)先手取數(shù)的最大答案。轉(zhuǎn)移顯然為
\(f_{i,j}=sum_j-sum_i-min{f_{k,j},f_{i,k}}\),其中滿足\(i~<~k~<~j\)。枚舉\(k\)進行轉(zhuǎn)移,復(fù)雜度是\(O(n^3)\)。直接涼涼。
狀態(tài)已經(jīng)是\(O(n^2)\)無法優(yōu)化。考慮對轉(zhuǎn)移進行優(yōu)化。考慮枚舉\(k\)是求一定區(qū)間內(nèi)\(f\)的最大值。這個\(f\)的區(qū)間是從小到大枚舉的,所以可以維護區(qū)間內(nèi)\(f\)的最大值。具體的,設(shè)\(l_{i,j}\)代表\(max{f_{i,k}}\),\(r_{i,j}\)代表\(max{f_{k,r}}\),其中滿足\(i~<~k~<~j\)。
這樣轉(zhuǎn)移方程就變成\(f_{i,j}=sum_j-sum_i-min{l_{i,j},r_{i,j}}\)。這樣使用DP對DP進行優(yōu)化,轉(zhuǎn)移變成\(O(1)\)的,可以通過本題。
其中\(l_{i,j}=max{l_{i,j-1},f_{i,j}}\),\(r\)的轉(zhuǎn)移同理。
Code
#include<cstdio> #include<cstring> #define rg register #define ci const int #define cl const long long inttypedef 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因為復(fù)雜度較高而無法承受時,考慮對轉(zhuǎn)移進行優(yōu)化。常見的如維護區(qū)間最大/最小值,通過數(shù)據(jù)結(jié)構(gòu)或者DP進行優(yōu)化。
轉(zhuǎn)載于:https://www.cnblogs.com/yifusuyi/p/9570829.html
總結(jié)
以上是生活随笔為你收集整理的【DP优化】【P1430】序列取数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谈一下对绩效和自身技能发展的理解
- 下一篇: [Go]通道(channel)的基本操作