SGU_222
最近刚学了插头dp,所以就用插头dp那个模式写了这个题。
可以用f[i][j][st]表示推到第i行第j列时,行和列上rook的状态为st时方案的种数。
#include<stdio.h> #include<string.h> #define HASH 30007 #define SIZE 1000010 int N, K, rst, cst; 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]; int encode(int rst, int cst) { return (rst << N) | cst; } void decode(int st) { cst = st & ((1 << N) - 1); rst = st >> N; } void dpblank(int i, int j, int cur) { int k; for(k = 0; k < hm[cur].size; k ++) { decode(hm[cur].state[k]); hm[cur ^ 1].push(hm[cur].state[k], hm[cur].f[k]); if(((1 << i) & rst) == 0 && ((1 << j) & cst) == 0) hm[cur ^ 1].push(encode(rst | (1 << i), cst | (1 << j)), hm[cur].f[k]); } } void solve() { int i, j, k, cur = 0; long long ans = 0; hm[cur].init(); hm[cur].push(0, 1); for(i = 0; i < N; i ++) for(j = 0; j < N; j ++) { hm[cur ^ 1].init(); dpblank(i, j, cur); cur ^= 1; } for(i = 0; i < hm[cur].size; i ++) { decode(hm[cur].state[i]); for(j = k = 0; j < N; j ++) if(rst & (1 << j)) ++ k; if(k == K) ans += hm[cur].f[i]; } printf("%I64d\n", ans); } int main() { while(scanf("%d%d", &N, &K) == 2) { if(K > N) printf("0\n"); else solve(); } return 0; }