原题地址:http://codeforces.com/contest/1051/problem/D
题意:对 2 × n 2×n 2×n格子着色,仅能着黑色或白色,问色块数为 k k k的着色方案有多少种。色块定义如下,若两个格子颜色相同且相邻,则属于同一色块;若两个格子颜色相同且所属色块相邻,则属于同一色块;否则属于不同色块。
思路:这题的矩阵很有特点,是 2 × n 2×n 2×n,那么就可以很容易的想到是利用状态压缩来进行转移.我们设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前 i i i列,第 i i i列的状态是 j j j,色块数为 k k k的方案数
那么对于每一个 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]都可以由四种状态得来.所以只需要枚举列数和色块数,然后每次转移16次就行了.
具体转移参考代码
#include
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 998244353;
ll dp[1005][10][2005];//表示前i列,第i列的状态是j,色块数为k的方案数
int n, k;
int main() {
scanf("%d%d", &n, &k);
dp[1][0][1] = 1;
dp[1][1][2] = 1;
dp[1][2][2] = 1;
dp[1][3][1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= k; j++) {
dp[i][0][j] += dp[i - 1][0][j];
dp[i][0][j] += dp[i - 1][1][j];
dp[i][0][j] += dp[i - 1][2][j];
dp[i][0][j] += dp[i - 1][3][j - 1];
dp[i][1][j] += dp[i - 1][0][j - 1];
dp[i][1][j] += dp[i - 1][1][j];
if(j!=1)dp[i][1][j] += dp[i - 1][2][j - 2];
dp[i][1][j] += dp[i - 1][3][j - 1];
dp[i][2][j] += dp[i - 1][0][j - 1];
if(j!=1)dp[i][2][j] += dp[i - 1][1][j - 2];
dp[i][2][j] += dp[i - 1][2][j];
dp[i][2][j] += dp[i - 1][3][j - 1];
dp[i][3][j] += dp[i - 1][0][j - 1];
dp[i][3][j] += dp[i - 1][1][j];
dp[i][3][j] += dp[i - 1][2][j];
dp[i][3][j] += dp[i - 1][3][j];
for (int k = 0; k < 4; k++) dp[i][k][j] %= mod;
}
}
ll ans = 0;
for (int i = 0; i < 4; i++) ans += dp[n][i][k];
ans %= mod;
printf("%lld\n", ans);
return 0;
}