BZOJ-1566: [NOI2009]管道取珠(DP)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1566

事实上求sigma(ai^2)可以理解成求操作序列A与操作序列B产生的结果一样的(A,B)的对数,那么DP,令dp[i][][k][h]表示A上面取了i个,下面取了j个,B上面取了k个,下面取了h个的方案数,然后DP,然后h这一维可以压掉。

代码:

#include 

 

#define rep( i , l , r ) for ( int i = l ; i <= r ; ++ i )

#define update( x , y ) ( x += y ) %= mod ;

 

const int mod = 1024523 , maxn = 510 ;

 

int dp[ maxn ][ maxn ][ maxn ] , n , m ;

char s[ 2 ][ maxn ] ;

 

int main(  ) {

        scanf( "%d%d" , &n , &m ) ;

        scanf( "%s%s" , s[ 0 ] + 1 , s[ 1 ] + 1 ) ;

        rep( i , 0 , n ) rep( j , 0 , m ) rep( k , 0 , n ) dp[ i ][ j ][ k ] = 0 ;

        dp[ 0 ][ 0 ][ 0 ]= 1 ;

        rep( i , 0 , n ) rep( j , 0 , m ) rep( k , 0 , n ) if ( dp[ i ][ j ][ k ] ) {

                if ( s[ 0 ][ i + 1 ] == s[ 0 ][ k + 1 ] ) update( dp[ i + 1 ][ j ][ k + 1 ] , dp[ i ][ j ][ k ] ) ;

                if ( s[ 0 ][ i + 1 ] == s[ 1 ][ i + j - k + 1 ] ) update( dp[ i + 1 ][ j ][ k ] , dp[ i ][ j ][ k ] ) ;

                if ( s[ 1 ][ j + 1 ] == s[ 0 ][ k + 1 ] ) update( dp[ i ][ j + 1 ][ k + 1 ] , dp[ i ][ j ][ k ] ) ;

                if ( s[ 1 ][ j + 1 ] == s[ 1 ][ i + j - k + 1 ] ) update( dp[ i ][ j + 1 ][ k ] , dp[ i ][ j ][ k ] ) ;

        }

        printf( "%d\n" , dp[ n ][ m ][ n ] ) ;

        return 0 ;

}

你可能感兴趣的:(BZOJ-1566: [NOI2009]管道取珠(DP))