intさわだんのBlack History

刹那的レジェンドになりたい。

ICPC 国内予選2003C The Secret Number AOJ1126

イキってDPで解いたら実装重くて痛い目にあった
集中してやったのでバグは起きなかった。

dp[i][j][0] : 場所i,jをスタート地点にした時の数字の桁の最大数
dp[i][j][1~] : 最大の時の数字の列

これを i = h-1, j = w-1 (一番右下のブロック)から i=0,j=0 までをDPする
つまり漸化式の根幹は、
i,jが数字の時 : dp[i][j][0] = max(1,dp[i+1][j][0],dp[i][j+1][0])

#include <bits/stdc++.h>
#include <map>
#define chmin(a, b) ((a)=min((a), (b)))
#define chmax(a, b) ((a)=max((a), (b)))
#define fs first
#define sc second
#define eb emplace_back
using namespace std;
 
typedef long long ll;
typedef pair<int, int> P;
typedef tuple<int, int, int> T;
 
const ll MOD=1e9+7;
const ll INF=1e18;
 
int dx[]={1, -1, 0, 0};
int dy[]={0, 0, 1, -1};


char num[] = "0123456789";
int di[] = {1,0};
int dj[] = {0,1};

bool check(int len,int a[80],int b[80]){
    for(int i = 1;i <= len;i++){
        if(a[i] == b[i]) continue;
        else if(a[i] > b[i]){
            return true;
        }else{
            return false;
        }
    }
    return false;
}

int dp[80][80][80] = {0};

int main(){
    int w,h;
    char tmp[80][80];
    int mat[80][80];
    while(1){
        cin >> w >> h;
        if(w == 0)break;
        for(int i = 0;i < h;i++) cin >> tmp[i];

        for(int i = 0;i < 80;i++){
            for(int j = 0;j < 80;j++){
                for(int k = 0;k < 80;k++){
                    dp[i][j][k] = 0;
                }
            }
        }
        
        for(int i = 0;i < h;i++){ // char から int にする
            for(int j = 0;j < w;j++){
                mat[i][j] = -1;
                for(int k = 0;k <= 9;k++) if(num[k] == tmp[i][j]) mat[i][j] = k;
            }
        }
        
        
        int maxlen = 0,ans[80] = {0};
        for(int i = 0;i < h;i++) mat[i][w] = -1;
        for(int j = 0;j < w;j++) mat[h][j] = -1;
        
        
        for(int i = h-1;i >= 0;i--){
            for(int j = w-1;j >= 0;j--){
                if(mat[i][j] == -1) continue;
                dp[i][j][0] = 1; dp[i][j][1] = mat[i][j];
                if(mat[i][j] != 0 && maxlen <= 1){
                    maxlen = 1;
                    ans[1] = max(ans[1],mat[i][j]);
                }
                for(int k = 0;k < 2;k++){
                    int ni = i+di[k],nj = j+dj[k];
                    if(mat[ni][nj] == -1)continue;
                    if(1 + dp[ni][nj][0] > dp[i][j][0]){ // 必ず値を更新すべき場合
                        dp[i][j][0] = 1 + dp[ni][nj][0];
                        for(int ii = 0;ii < dp[ni][nj][0];ii++){
                            dp[i][j][ii+2] = dp[ni][nj][ii+1];
                        }
                        if(mat[i][j] != 0 &&  (dp[i][j][0] > maxlen || (dp[i][j][0] == maxlen && check(maxlen,dp[i][j],ans) == true))){
                            maxlen = dp[i][j][0];
                            for(int q = 1;q <= maxlen;q++) ans[q] = dp[i][j][q];
                        }
                    }else if(1 + dp[ni][nj][0] == dp[i][j][0]){ //確認が必要な場合
                        int cand[80];
                        cand[1] = mat[i][j];
                        for(int q = 0;q < dp[ni][nj][0];q++){
                            cand[q+2] = dp[ni][nj][q+1];
                        }
                        if(check(dp[i][j][0],cand,dp[i][j]) == true){
                            for(int q = 0;q < dp[ni][nj][0];q++) dp[i][j][q+2] = cand[q+2];
                        }
                        if(mat[i][j] != 0 &&  (dp[i][j][0] > maxlen || (dp[i][j][0] == maxlen && check(maxlen,dp[i][j],ans) == true))){
                            maxlen = dp[i][j][0];
                            for(int q = 1;q <= maxlen;q++) ans[q] = dp[i][j][q];
                        }
                    }
                }
            }
        }
        
        for(int i = 1;i <= maxlen;i++){
            cout << ans[i];
        }
        cout << endl;
        
    }
}