洛谷P1005&NOIP2007 矩阵取数游戏

(抄的高精度模板233

由于要取完所有的数,所以原题可转化为在每一行上取数,累加所有行的答案即可

f[k][I][j]表示在第k行从1取到I,从j取到m的答案

f[k][I][j]=max(f[k][I-1][j]+2^(m-j+i-1)*a[k][I-1],f[k][i][j+1]+2^(m-j+i-1)*a[k][j+1])

(第一次写把a[k][I-1]习惯性地写成了a[I-1][j],调了好久。。。。

(刚开始本想加一维表示第几次取,然后发现当I和j固定时,次数就固定了。。。。

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define dp f
#define maxn 82
using namespace std;
struct BIGNUM {
    short num[35],len;
    BIGNUM(){memset(num,0,sizeof(num));len=1;}
    BIGNUM operator = (const char str[]) {
        len=strlen(str);
        for(int i=0;i<len;i++)
            num[i]=str[len-i-1]-'0';
        while(num[len-1]==0&&len>1) len--;
        return *this;
    }
    BIGNUM operator = (const int n) {
        int tmp=n;
        len=1;
        do {
            num[len-1]=tmp%10;
            tmp/=10;len++;
        }while(tmp>0);
        while(num[len-1]==0&&len>1) len--;
        return *this;
    }
    BIGNUM operator + (const BIGNUM &rhs) const {
        BIGNUM tmp;
        tmp.len=max(len,rhs.len)+1;
        for(int i=0;i<tmp.len;i++) {
            tmp.num[i]+=num[i]+rhs.num[i];
            tmp.num[i+1]=tmp.num[i]/10;
            tmp.num[i]%=10;
        }
        while(tmp.num[tmp.len-1]==0&&tmp.len>1) tmp.len--;
        return tmp;
    }
    BIGNUM operator * (const BIGNUM &rhs) const {
        BIGNUM tmp;
        tmp.len=len+rhs.len;
        for(int i=0;i<len;i++)
            for(int j=0;j<rhs.len;j++) {
                tmp.num[i+j]+=num[i]*rhs.num[j];
                tmp.num[i+j+1]+=tmp.num[i+j]/10;
                tmp.num[i+j]%=10;
            }
        while(tmp.num[tmp.len-1]==0&&tmp.len>1) tmp.len--;
        return tmp;
    }
    bool operator < (const BIGNUM &rhs) const {
        if(len>rhs.len) return false;
        if(len<rhs.len) return true;
        for(int i=len-1;i>=0;i--)
            if(num[i]!=rhs.num[i]) return num[i]<rhs.num[i];
        return false;
    }
    void print() {
        for(int i=len-1;i>=0;i--) printf("%d",num[i]);
    }
};
BIGNUM dp[82][82][82],ans,a[maxn][maxn];
int main(){
    ios::sync_with_stdio(false);
    int n,m;cin>>n>>m;
    int a0[82][82];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            cin>>a0[i][j];
            a[i][j]=a0[i][j];
    }
    BIGNUM pow[82];
    pow[0]=1;pow[1]=2;
    for(int i=2;i<=maxn-1;i++)
        pow[i]=pow[i-1]*pow[1];
    for(int k=1;k<=n;k++){
        BIGNUM ansx;
        for(int i=1;i<=m;i++){
            for(int j=m;j>=i-1;j--){
                int t=m-(j-i)-1;
                BIGNUM lf=dp[k][i-1][j],ri=dp[k][i][j+1];
                BIGNUM scl=pow[t]*a[k][i-1];
                BIGNUM scr=pow[t]*a[k][j+1];
                BIGNUM s=max(lf+scl,ri+scr);
                dp[k][i][j]=s;
            }
            ansx=max(ansx,dp[k][i][i-1]);
        }
        ans=ansx+ans;
    }
    ans.print();
    return 0;
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值