Codevs1166 矩阵取数游戏
2015-09-26 10:44
441 查看
首先吐槽:先是高精加忘了进位时要用+=,WA了几发;后来是高精乘单精写不对,被迫写高精乘高精,这样一来又WA了几发;高精写好后,发现居然T了,于是改成多压几位(多压几位也是可以节省时间的),然而还是T,并没有什么L用;于是再次发现,我居然用了O(n∗m3n*m^3)的算法,被迫改为O(n∗m2n*m^2);于是乎,不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也可以达到同样的效果,这样就省去了对于2i2^i的计算。在枚举时,我刚开始的思路是,用k确定最内层的元素(即最后取走的那一个),再利用i从k到1、j从k到m进行扩展,但这样的做法是O(n∗m3n*m^3),加上高精就会T,于是得到这样的一个思路,就是用k枚举区间长度从小到大(这样可以保证在计算长度为k的区间时所要用到的长度为k-1的区间值均已计算过),用i枚举区间左端点,这样区间右端点j就可以得出了,即j=i+k-1,不用再花费O(m)的时间去枚举右端点了,这样时间复杂度优化为O(n∗m2n*m^2)。当然空间上也是可以优化的,由于每行数是相互独立的,我们可以每次只读取一行进行处理。
代码如下:
说一下思路:区间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也可以达到同样的效果,这样就省去了对于2i2^i的计算。在枚举时,我刚开始的思路是,用k确定最内层的元素(即最后取走的那一个),再利用i从k到1、j从k到m进行扩展,但这样的做法是O(n∗m3n*m^3),加上高精就会T,于是得到这样的一个思路,就是用k枚举区间长度从小到大(这样可以保证在计算长度为k的区间时所要用到的长度为k-1的区间值均已计算过),用i枚举区间左端点,这样区间右端点j就可以得出了,即j=i+k-1,不用再花费O(m)的时间去枚举右端点了,这样时间复杂度优化为O(n∗m2n*m^2)。当然空间上也是可以优化的,由于每行数是相互独立的,我们可以每次只读取一行进行处理。
代码如下:
#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; }
相关文章推荐
- POJ - 3616 Milking Time(DAG)
- .c和.h档
- 心灵鸡汤
- sourceinsight 无法搜索类似 .s .S .kconfig文件的解决办法
- hdu5249KPI【treap】
- 生活随笔:折腾的家具
- 2015/9/26,中秋前一天
- 【Odoo】XML_RPC访问Odoo数据库
- https 基础
- 浅析 PHP 官方自动化测试方法
- QtQuick桌面应用程序开发指导 3)达到UI而功能_B 4)动态管理Note物_A
- POJ - 2533 Longest Ordered Subsequence(最长上升子序列)
- POJ 1442 Black Box【treap模板】
- javascript图片随滚动条置顶
- Scanner vs. StringTokenizer vs. String.Split
- Linux下dpkg命令常用方法整理
- 印象比较深刻的几次面试
- Android UI之ListView+CheckBox(避免抢占焦点)
- Java上机课后实践
- POJ - 1458 Common Subsequence(最长公共子序列)