首先吐槽:先是高精加忘了进位时要用+=,WA了几发;后来是高精乘单精写不对,被迫写高精乘高精,这样一来又WA了几发;高精写好后,发现居然T了,于是改成多压几位(多压几位也是可以节省时间的),然而还是T,并没有什么L用;于是再次发现,我居然用了O( n∗m3 )的算法,被迫改为O( n∗m2 );于是乎,不T了,WA了三个点;最后发现,改算法时我把区间长度当成了n而不是m(就这还能过7个点我也是醉了),于是,就AC了……
说一下思路:区间DP,状态转移方程为f[i][j]=2*max{f[i+1][j]+a[i],f[i][j-1]+a[j]},目标f[1][m],预处理f[i][i]=2*a[i]。这个意思这是,我们不必非要从两头开始取(即从外往里取),从里往外取,每次取乘2也可以达到同样的效果,这样就省去了对于 2i 的计算。在枚举时,我刚开始的思路是,用k确定最内层的元素(即最后取走的那一个),再利用i从k到1、j从k到m进行扩展,但这样的做法是O( n∗m3 ),加上高精就会T,于是得到这样的一个思路,就是用k枚举区间长度从小到大(这样可以保证在计算长度为k的区间时所要用到的长度为k-1的区间值均已计算过),用i枚举区间左端点,这样区间右端点j就可以得出了,即j=i+k-1,不用再花费O(m)的时间去枚举右端点了,这样时间复杂度优化为O( n∗m2 )。当然空间上也是可以优化的,由于每行数是相互独立的,我们可以每次只读取一行进行处理。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct bignum
{
long long len,a[105];
bignum()
{
len=1;
memset(a,0,sizeof(a));
}
bignum (long long num)
{
*this=num;
}
bignum operator + (const bignum &b)
{
bignum c;
c.len=max(len,b.len);
for (long long i=1;i<=c.len;++i)
{
c.a[i]+=a[i]+b.a[i];
c.a[i+1]+=c.a[i]/100000000;
c.a[i]%=100000000;
}
if (c.a[c.len+1]>0)
c.len++;
return c;
}
bignum operator += (const bignum &b)
{
*this=*this+b;
return *this;
}
bignum operator * (const bignum &two)
{
bignum b;
long long i,j;
b.len=len+two.len;
for (i=1;i<=len;++i)
for (j=1;j<=two.len;++j)
{
b.a[i+j-1]+=a[i]*two.a[j];
b.a[i+j]+=b.a[i+j-1]/100000000;
b.a[i+j-1]%=100000000;
}
while (!b.a[b.len] && b.len>1)
b.len--;
return b;
}
bignum operator *= (const bignum &a)
{
*this=(*this)*a;
return *this;
}
bool operator < (const bignum &b) const
{
if (len!=b.len)
return len<b.len ? 1:0 ;
for (long long i=len;i>=1;--i)
if (a[i]!=b.a[i])
return a[i]<b.a[i] ? 1:0 ;
return 1;
}
bignum operator = (long long num)
{
memset(a,0,sizeof(a));
len=0;
while (num!=0)
{
a[++len]=num%10000000;
num/=10000000;
}
return *this;
}
};
long long n,m;
bignum na[85];
bignum ans,f[85][85];
bignum two=2;
void print(bignum x)
{
printf("%lld",x.a[x.len]);
for (int i=x.len-1;i>=1;--i)
printf("%08lld",x.a[i]);
}
void dp()
{
long long i,j,k;
for (k=2;k<=m;++k)
for (i=1;i<=m;++i)
{
if (i+k>m+1)
continue;
j=i+k-1;
bignum a1=f[i+1][j]+na[i];
bignum a2=f[i][j-1]+na[j];
f[i][j]=max(a1,a2);
f[i][j]*=two;
}
ans+=f[1][m];
}
void init()
{
scanf("%lld%lld",&n,&m);
for (long long i=1;i<=n;++i)
{
for (long long j=1;j<=m;++j)
{
long long tmp;
scanf("%lld",&tmp);
na[j]=tmp;
f[j][j]=na[j]*two;
}
dp();
}
print(ans);
}
int main()
{
init();
return 0;
}