题目链接:Turn Game
dp套dp。逐行dp,枚举每一行的状态,向下转移。状态即每一列上是否有列覆盖住这一行。
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL ;
typedef vector < int > vi ;
typedef map < LL , int > mpvi ;
#define clr( a , x ) memset ( a , x , sizeof a )
const int mod = 1e9 + 7 ;
int val[16] = { 0 , 1 , 1 , 1 , 1 , 2 , 1 , 1 , 1 , 2 , 2 , 2 , 1 , 2 , 1 , 1 } ;
int num[16] = { 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 } ;
int res[5][11][41] ;
int tmp[17] , nxt[17] ;
LL p[20] ;
mpvi dp[2] ;
mpvi :: iterator it ;
void up ( int& x , int y ) {
x += y ;
if ( x >= mod ) x -= mod ;
}
void init ( int a[] , int x , int y , int n ) {
a[n] = x ;
for ( int i = 0 ; i < n ; ++ i ) {
a[i] = y + x ;
}
}
void decode ( LL a , int n ) {
int x = a / p[n] ;
tmp[n] = x ;
for ( int i = 0 ; i < n ; ++ i ) {
tmp[i] = a % 10 + x ;
a /= 10 ;
}
}
LL encode ( int a[] , int n ) {
LL res = a[n] ;
for ( int i = n - 1 ; ~i ; -- i ) {
res = res * 10 + ( a[i] - a[n] ) ;
}
return res ;
}
void preprocess () {
p[0] = 1 ;
for ( int i = 1 ; i < 20 ; ++ i ) {
p[i] = p[i - 1] * 10 ;
}
for ( int m = 1 ; m <= 4 ; ++ m ) {
int cur = 0 ;
init ( tmp , 0 , 6 , 1 << m ) ;
tmp[0] = 0 ;
dp[0].clear () ;
dp[0][encode ( tmp , 1 << m )] = 1 ;
for ( int n = 1 ; n <= 10 ; ++ n ) {
cur ^= 1 ;
dp[cur].clear () ;
mpvi& pre = dp[cur ^ 1] ;
for ( it = pre.begin () ; it != pre.end () ; ++ it ) {
decode ( it->first , 1 << m ) ;
for ( int i = 0 ; i < 1 << m ; ++ i ) {
init ( nxt , 41 , 0 , 1 << m ) ;
int minv = 41 ;
for ( int j = 0 ; j < 1 << m ; ++ j ) if ( tmp[j] <= n + m - 1 ) {
for ( int k = 0 ; k < 1 << m ; ++ k ) {
int x = tmp[j] + num[k] - num[j & k] + val[i ^ k] ;
nxt[k] = min ( nxt[k] , x ) ;
minv = min ( x , minv ) ;
}
}
nxt[1 << m] = minv ;
up ( res[m][n][minv] , it->second ) ;
up ( dp[cur][encode ( nxt , 1 << m )] , it->second ) ;
}
}
for ( int i = 1 ; i <= 40 ; ++ i ) {
up ( res[m][n][i] , res[m][n][i - 1] ) ;
}
}
}
}
int main () {
preprocess () ;
//printf ( "%.5f\n" , ( double ) clock () / CLOCKS_PER_SEC ) ;
/*
printf ( "res[5][11][41] = { " ) ;
for ( int i = 0 ; i <= 4 ; ++ i ) {
for ( int j = 0 ; j <= 10 ; ++ j ) {
for ( int k = 0 ; k <= 40 ; ++ k ) {
printf ( "%d , " , res[i][j][k] ) ;
}
}
}
printf ( "} ;\n" ) ;
*/
int T , n , m , k ;
scanf ( "%d" , &T ) ;
for ( int i = 1 ; i <= T ; ++ i ) {
scanf ( "%d%d%d" , &n , &m , &k ) ;
printf ( "Case #%d: %d\n" , i , res[n][m][k] ) ;
}
return 0 ;
}