「Bzoj 1087」「SCOI2005」互不侵犯King (状压DP)

Bzoj 1087
设$dp(i,j,st(S))$为前$i$行安放了$j$个国王,$i$行使用$st(S)$状态的方案数。
$$dp(i,j,st(S))=\sum dp(i-1.j-num_s, st(k))$$
其中$st(S)$与$st(k)$不冲突。
初值:$dp(1, num(S), st(S)) = 1$,其中$S$是合法状态,其他值设为$0$。
然后求解即可,注意答案只在最后一行,累加不要加错了,然后dp数组也要开longlong,否则WA

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
const int MAXN = 9 + 2, MAXK = 100 + 5;
int n, m, st[1 << MAXN], num[1 << MAXN], tot;
LL dp[MAXN][MAXK][1 << MAXN];
int count(int S) {
    int ret = 0, t = S;
    while (t) ret++, t &= (t - 1); 
    return ret;
}
bool check(int S) {
    if (S & (S >> 1)) return false;
    return true;
}
bool check2(int a, int b) {
    int ta = a, x = 1;
    while (ta) {
        if (ta & 1 == 1) {
            if (x < n && ((b >> (x)) & 1) == 1) return false;
            if (x - 1 >= 0 && ((b >> (x - 1)) & 1) == 1) return false;
            if (x - 2 >= 0 && ((b >> (x - 2)) & 1) == 1) return false;
        }
        ta >>= 1, x++;
    }
    return true;
}
void clean() {
    ms(num, 0), ms(st, 0), ms(dp, 0), tot = 0;
}
void solve() {
    clean();
    for (int S=0;S<(1<<n);S++) if (check(S)) st[++tot] = S, num[tot] = count(S);
    for (int i=1;i<=tot;i++) dp[1][num[i]][i] = 1;
    for (int i=2;i<=n;i++) {
        for (int j=0;j<=m;j++) {
            for (int k=1;k<=tot;k++) {
                for (int l=1;l<=tot;l++) {
                    if (!check2(st[l], st[k])) continue;
                    dp[i][j][k] += dp[i - 1][j - num[k]][l];
                }
            }
        }
    }
    LL ans = 0;
    for (int j=1;j<=tot;j++) {
        ans += dp[n][m][j];
    }
    printf("%lld\n", ans);
}
int main() {
    #ifndef ONLINE_JUDGE 
    freopen("1.in", "r", stdin);freopen("1.out", "w", stdout);
    #endif
    scanf("%d%d", &n, &m), solve();
    return 0;
}
------ 本文结束 ------