HDU 4363
这题是记忆化搜索很容易想到,但状态却不好设
dp[i][j][u][d][l][r][k]。对于矩形为i*j,它的四周的颜色分别为u,d,l,r,横竖切的状态为k的种数。
其中要注意一个问题是,停止不一定是不可进行,而是随时都可以停止,这样就会有一种涂色为对某个矩形而言只涂一种颜色。那么,就必定会有重复的上下矩形只涂两种颜色的重复出现,这样就要减去这些重复的。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define LL __int64 using namespace std ; const LL MOD=1000000007; LL dp[42][42][5][5][5][5][2]; void dfs(int i,int j,int u,int d,int l,int r,int w){ if(dp[i][j][u][d][l][r][w]!=-1) return ; LL ret=0; for(int c=1;c<=4;c++){ if(c!=u&&c!=d&&c!=l&&c!=r) ret++; } if(w==1){ for(int h=1;h<i;h++){ for(int c=1;c<=4;c++){ if(c!=u&&c!=l&&c!=r){ dfs(i-h,j,c,d,l,r,0); ret=(ret+dp[i-h][j][c][d][l][r][0])%MOD; } } for(int c=1;c<=4;c++){ if(c!=d&&c!=l&&c!=r){ dfs(h,j,u,c,l,r,0); ret=(ret+dp[h][j][u][c][l][r][0])%MOD; } } } LL counts=0; for(int c1=1;c1<=4;c1++){ if(c1!=u&&c1!=l&&c1!=r){ for(int c2=1;c2<=4;c2++){ if(c2!=l&&c2!=r&&c2!=c1&&c2!=d) counts++; } } } counts=counts*(i-1); ret=((ret-counts)%MOD+MOD)%MOD; } else{ for(int k=1;k<j;k++){ for(int c=1;c<=4;c++){ if(c!=u&&c!=l&&c!=d){ dfs(i,j-k,u,d,c,r,1); ret=(ret+dp[i][j-k][u][d][c][r][1])%MOD; } } for(int c=1;c<=4;c++){ if(c!=u&&c!=r&&c!=d){ dfs(i,k,u,d,l,c,1); ret=(ret+dp[i][k][u][d][l][c][1])%MOD; } } } LL counts=0; for(int c1=1;c1<=4;c1++){ if(c1!=u&&c1!=l&&c1!=d){ for(int c2=1;c2<=4;c2++){ if(c2!=c1&&c2!=r&&c2!=u&&c2!=d) counts++; } } } counts=counts*(j-1); ret=((ret-counts)%MOD+MOD)%MOD; } dp[i][j][u][d][l][r][w]=ret; } int main(){ memset(dp,-1,sizeof(dp)); int T,n,m; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); dfs(n,m,0,0,0,0,1); printf("%I64d\n",dp[n][m][0][0][0][0][1]); } return 0; }
写的时候要特别小心,很容易出现BUG。调了我一晚上。