0w1

台北市104 學年度資訊學科能力競賽 pD. Guess ( DP )

f:id:h0rnet:20161018233127j:plain
dp[ i ][ j ] : 考慮完 B 字串的第 i 個字元,其尾端有 j 個字元是 A 字串的前綴,且B不含A,此時修改次數的最小值。
修改最後一個字元之後,尋找其最長的後綴使 A 的前綴與之相同。這部分用預處理。

#include <bits/stdc++.h>
using namespace std;

typedef vector< int > vi;
typedef vector< vi > vvi;

const int INF = 0x3f3f3f3f;

template< class T1, class T2 >
int upmin( T1 &x, T2 v ){
    if( x > v ){
        x = v;
        return 1;
    }
    return 0;
}

template< class T1, class T2 >
int upmax( T1 &x, T2 v ){
    if( x < v ){
        x = v;
        return 1;
    }
    return 0;
}

string A, B;

void init(){
    cin >> A >> B;
}

void solve(){
    vvi nxt( A.size(), vi( 2 ) );
    for( int i = 0; i < A.size(); ++i ){
        for( int k = 0; k < 2; ++k ){
            string x = A.substr( 0, i + 1 );
            string y = x.substr( 0, x.size() - 1 ) + ( char )( ( x.back() - 'A' + k ) % 2 + 'A' );
            for( int j = ( int )x.size(); j >= 0; --j ){
                string s = x.substr( 0, j );
                string t = y.substr( y.size() - j );
                if( s == t ){
                    nxt[ i ][ k ] = j;
                    break;
                }
            }
        }
    }

    vvi dp( B.size() + 1, vi( A.size() + 1, INF ) );
    dp[ 0 ][ 0 ] = 0;
    for( int i = 0; i < B.size(); ++i )
        for( int j = 0; j < A.size(); ++j ){
            if( B[ i ] == A[ j ] ){ // assert( nxt[ j ][ 0 ] == j + 1 );
                upmin( dp[ i + 1 ][ nxt[ j ][ 0 ] ], dp[ i ][ j ] );
                upmin( dp[ i + 1 ][ j ], dp[ i ][ j ] + 1 );
            } else{
                upmin( dp[ i + 1 ][ nxt[ j ][ 1 ] ], dp[ i ][ j ] );
                upmin( dp[ i + 1 ][ j ], dp[ i ][ j ] + 1 );
            }
        }

    int ans = INF;
    for( int i = 0; i < A.size(); ++i )
        upmin( ans, dp[ B.size() ][ i ] );
    cout << ans << endl;
}

signed main(){
    ios::sync_with_stdio( 0 );
    init();
    solve();
    return 0;
}