NOIP2007矩陣取數[DP|高精度]

題目描述

帥帥常常跟同窗玩一個矩陣取數遊戲:對於一個給定的n*m的矩陣,矩陣中的每一個元素aij均爲非負整數。遊戲規則以下:ios

1.每次取數時須從每行各取走一個元素,共n個。m次後取完矩陣全部元素;數組

2.每次取走的各個元素只能是該元素所在行的行首或行尾;spa

3.每次取數都有一個得分值,爲每行取數的得分之和,每行取數的得分 = 被取走的元素值*2^i,其中i表示第i次取數(從1開始編號);調試

4.遊戲結束總得分爲m次取數得分之和。code

帥帥想請你幫忙寫一個程序,對於任意矩陣,能夠求出取數後的最大得分。blog

輸入輸出格式

輸入格式:遊戲

輸入文件game.in包括n+1行:ci

第1行爲兩個用空格隔開的整數n和m。string

第2~n+1行爲n*m矩陣,其中每行有m個用單個空格隔開的非負整數。io

數據範圍:

60%的數據知足:1<=n, m<=30,答案不超過10^16

100%的數據知足:1<=n, m<=80,0<=aij<=1000

 

輸出格式:

輸出文件game.out僅包含1行,爲一個整數,即輸入矩陣取數後的最大得分。

輸入輸出樣例

輸入樣例#1:
2 3
1 2 3
3 4 2
輸出樣例#1:
82

說明

NOIP 2007 提升第三題

-------------------------------------

DP

行與行之間相互獨立,各行單獨求解;必定先清空

f(i,j)左選了i個,右選了j個的最大得分

狀態轉移很好想,注意邊界處理

高精度[此次從數組1開始]

高加高,高乘低

輸出時必定當心0

建議先寫出long long 的方便調試

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=85;
const int B=1e4,L=100;

struct big{
    int size,d[L];
    big(int a=1):size(a){memset(d,0,sizeof(int)*L);}
};

void jia(big &a,big &b){
    int g=0,i;
    for(i=1;;i++){
        if(g==0&&i>a.size&&i>b.size) break;
        int tmp=g;
        if(i<=a.size) tmp+=a.d[i];
        if(i<=b.size) tmp+=b.d[i];
        a.d[i]=tmp%B;
        g=tmp/B;
    }
    a.size=i-1;
}

void chengInt(big &a,int k){
    int g=0,i;
    for(i=1;i<=a.size;i++){
        int tmp=a.d[i]*k;
        a.d[i]=(tmp+g)%B;
        g=(tmp+g)/B;
    }
    while(g){
        a.d[++a.size]=g%B;
        g/=B;
    }
}

void copy(big &t,big &s){
    t.size=s.size;
    for(int i=1;i<=s.size;i++) t.d[i]=s.d[i];
}

big max(big &a,big &b){
    if(a.size>b.size) return a;
    if(a.size<b.size) return b;
    for(int i=a.size;i>=1;i--){
        if(a.d[i]>b.d[i]) return a;
        if(a.d[i]<b.d[i]) return b;
    }
    return a;
}


void print(big &a){
    for(int i=a.size;i>=1;i--){
        if(i==a.size);
        else if(a.d[i]<10) cout<<"0000";
        else if(a.d[i]<100) cout<<"00";
        else if(a.d[i]<1000) cout<<"0";
        cout<<a.d[i];
    }
    cout<<"\n";
}

int n,m;
int a[N][N];
big f[N][N];
big ans,fin=0;

big two[N];
void PRE(){
    two[0].d[1]=1;
    for(int i=1;i<=m+1;i++){
        copy(two[i],two[i-1]);
        chengInt(two[i],2);
    }
}
big sol(int num){
    ans=big();
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++) f[i][j]=big();
    
    f[1][0].d[1]=a[num][1]*2;
    f[0][1].d[1]=a[num][m]*2;
    for(int i=2;i<=m;i++){
//        f[i][0]=f[i-1][0]+a[num][i]*((ll)1<<i);
//        f[0][i]=f[0][i-1]+a[num][m-i+1]*((ll)1<<i);
        
        copy(f[i][0],f[i-1][0]);
        big tmp; copy(tmp,two[i]); chengInt(tmp,a[num][i]);
        jia(f[i][0],tmp);
        
        copy(f[0][i],f[0][i-1]);
        big tmp2; copy(tmp2,two[i]); chengInt(tmp2,a[num][m-i+1]);
        jia(f[0][i],tmp2);
        
    }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=m-i;j++){
//            f[i][j]=max(f[i-1][j]+a[num][i]*((ll)1<<(i+j)),
//                        f[i][j-1]+a[num][m-j+1]*((ll)1<<(i+j)));
        
            big x,y;
            copy(x,f[i-1][j]);
            big tmp; copy(tmp,two[i+j]); chengInt(tmp,a[num][i]);
            jia(x,tmp);
            
            copy(y,f[i][j-1]);
            big tmp2; copy(tmp2,two[i+j]); chengInt(tmp2,a[num][m-j+1]);
            jia(y,tmp2);
            
            f[i][j]=max(x,y);
        }
    
    for(int i=0;i<=m;i++) ans=max(ans,f[i][m-i]);
    return ans;
}

int main(){//system("pause");
    cin>>n>>m;
    PRE();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    
    for(int i=1;i<=n;i++) {big tmp=sol(i);jia(fin,tmp);}
    print(fin);
    
}
相關文章
相關標籤/搜索