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
",dp[n][m][0][0][0][0][1]);
	}
	return 0;
}

  

写的时候要特别小心,很容易出现BUG。调了我一晚上。

原文地址:https://www.cnblogs.com/jie-dcai/p/4426286.html