BZOJ-1566: [NOI2009]管道取珠(DP)
2019-03-15 本文已影响0人
AmadeusChan
题目: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 <cstdio>
#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 ;
}