wikioi p1166 矩阵取数游戏

来源:互联网 发布:小型图书馆源码 编辑:程序博客网 时间:2024/04/24 18:48

这题是动规还好  问题是要加功能很齐全的高精度   一下子就变得恶心了

高精度没法说.....就不说了...

dp[i][j] 表示计算的那一层还剩下为 [ i , j ] 的区间 保存之前取数的最大值 

首先因为每一层求得最值都互不影响

所以for( res  1->n)枚举每一层的最大值

然后for( k  1->m)枚举第几次取数 同时计算2的k次幂

最后枚举左区间( L  1->k) 因为第k次取数该排最多只能取k个  所以L枚举到k就行了

通过k和L可以计算出右区间端点  R = m + L - 1 - k ;

动规方程为dp[L][R] = max(dp[L - 1][R] + (2^k )* map[res][L - 1], dp[L][R + 1] + (2^k) * map[res][R + 1])

每一层取完数字的最大值就是之前计算的dp[i][j]中的一个最大值 ans = max(dp[i][j] , ans) 

再吧ans累加即可得到答案

一开始看错题目了,以为是总共取M次,谁知道是每次M次,那这题就简单了,没的说。

但是高精度有点烦。

现在终于自己写出来了

/*Sour : NOIPSenior ID   : ThaddeusPID  : 1005*/#include<stdio.h>#include<iostream>#include<algorithm>#include<memory.h>using namespace std;const int maxn = 81;const int maxm = 5;const long long radix = 1000000000;long long a[maxn][maxn][maxm];long long f[maxn][maxn][maxn][maxm]; //第i行头取j~k的最大值 long long r[maxn][maxm]; //二进制数 long long ans[maxm];long long mul1[maxm];long long mul2[maxm];long long com1[maxm];long long com2[maxm];long long zero[maxm];long long two[maxm];long long temp[maxm];int n,m;void init(){int i,j;scanf("%d %d",&n,&m);for (i=1;i<=n;i++)for (j=1;j<=m;j++)scanf("%lld",&a[i][j][1]);}bool comp(long long x[],long long y[]) //判断数字x是否比y大,如果是,返回true {int i;for (i=maxm-1;i>=1;i--){if (x[i]>y[i]) return true;if (x[i]<y[i]) return false;}return true;}void plu(long long x[],long long y[],long long z[]) //将x与y相加的值记录到z中{int i;for (i=0;i<maxm;i++)z[i]=0;for (i=1;i<maxm;i++){z[i]+=x[i]+y[i];z[i+1]+=z[i]/radix;z[i]%=radix;}for (i=1;i<maxm;i++)z[i]+=z[i-1]/radix,z[i-1]%=radix;} void mult(long long x[],long long y[],long long z[])//将x与y相乘的值记录到z中{int i,j;for (i=0;i<maxm;i++)z[i]=0;for (i=1;i<maxm;i++)for (j=1;j<maxm;j++)if (i+j<=maxm){z[i+j-1]+=x[i]*y[j];z[i+j]+=z[i+j-1]/radix;z[i+j-1]%=radix;}for (i=0;i<maxm;i++){z[i+1]+=z[i]/radix;z[i]%=radix;}}void _put(long long x[]){int i;i = maxm-1;while(!x[i]&&i>1) --i;printf("%lld",x[i--]);for (;i>=1;i--)printf("%09lld",x[i]);}void _init(){int i;memset(ans,0,sizeof(ans));memset(f,0,sizeof(f));memset(zero,0,sizeof(zero));memset(two,0,sizeof(two));    memset(r,0,sizeof(r));two[1]=2;r[0][1]=1;for (i=1;i<=m;i++)mult(r[i-1],two,r[i]);}void work(){int i,j,k,p;for (i=1;i<=n;i++){for (j=1;j<=m;j++)mult(a[i][j],r[m],f[i][j][j]);for (p=1;p<=m;p++)for (j=1;j+p<=m;j++){k = p+j;mult(a[i][j],r[m-p],mul1);mult(a[i][k],r[m-p],mul2);plu(mul1,f[i][j+1][k],com1);plu(mul2,f[i][j][k-1],com2);if (comp(com1,com2))plu(com1,zero,f[i][j][k]);elseplu(com2,zero,f[i][j][k]);}}}void put(){int i;for (i=1;i<=n;i++)plu(ans,f[i][1][m],temp),plu(temp,zero,ans);_put(ans);}int main(){freopen("test.in","r",stdin);freopen("test.out","w",stdout);init();_init();work();put();return 0;}