SGU_223
最近刚学了插头dp,所以就用插头dp那个模式写了这个题。
如果逐格递推的话实际上只有这个格子左边、左上方、上方、右上方的格子会影响当前这个格子是否能够放king,所以在记录状态的时候可以把轮廓线上有无king作为一个状态,同时单记录轮廓线上的king没办法知道最后有多少个king,所以再在状态中留出7个二进制位记录一下已经放了几个king即可。
#include<stdio.h> #include<string.h> #define HASH 30007 #define SIZE 1000010 #define MAXD 15 int N, K, code[MAXD], num; struct Hashmap { int head[HASH], next[SIZE], state[SIZE], size; long long f[SIZE]; void init() { memset(head, -1, sizeof(head)); size = 0; } void push(int st, long long ans) { int i, h = st % HASH; for(i = head[h]; i != -1; i = next[i]) if(st == state[i]) { f[i] += ans; return ; } state[size] = st, f[size] = ans; next[size] = head[h]; head[h] = size ++; } }hm[2]; void decode(int *code, int m, int st) { int i; num = st & ((1 << 7) - 1); st >>= 7; for(i = m; i >= 0; i --) { code[i] = st & 1; st >>= 1; } } int encode(int *code, int m) { int i, st = 0; for(i = 0; i <= m; i ++) { st <<= 1; st |= code[i]; } st <<= 7; st |= num; return st; } void dpblank(int i, int j, int cur) { int k; for(k = 0; k < hm[cur].size; k ++) { decode(code, N + 1, hm[cur].state[k]); if(num < K && code[j - 1] == 0 && code[j] == 0 && code[j + 1] == 0 && code[j + 2] == 0) { ++ num; code[j] = 1; hm[cur ^ 1].push(encode(code, j == N ? N : N + 1), hm[cur].f[k]); -- num; } code[j] = 0; hm[cur ^ 1].push(encode(code, j == N ? N : N + 1), hm[cur].f[k]); } } void solve() { int i, j, cur = 0; long long ans = 0; hm[cur].init(); hm[cur].push(0, 1); memset(code, 0, sizeof(code)); for(i = 1; i <= N; i ++) for(j = 1; j <= N; j ++) { hm[cur ^ 1].init(); dpblank(i, j, cur); cur ^= 1; } for(i = 0; i < hm[cur].size; i ++) if((hm[cur].state[i] & ((1 << 7) - 1)) == K) ans += hm[cur].f[i]; printf("%I64d\n", ans); } int main() { while(scanf("%d%d", &N, &K) == 2) { solve(); } return 0; }