https://www.luogu.org/problemnew/show/P1896
dp[i][j][l] 三维状态
i表示第几行 j表示状态,l表示所用国王数
题中给了n最大为9 那么状态数就是1<<9
我们先预处理所需的数据,即某一状态是否合法,及当前状态所需的国王数
上下行需要满足 (h&j) == 0 && ((h<<1)&j) == 0 && ((h>>1)&j) == 0 即 国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子
然后叠加就可以了 记得开longlong 否则数据会爆int
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
const int M = 1e7 + 100;
const int INF = 0x3f3f3f3f;
const int mod = 100000000;
ll n,k,dp[20][(1<<10)+100][110],need[(1<<10)+100],vis[(1<<10)+100];
int main()
{
cin >> n >> k;
//预处理每种状态所需的国王数
for(int i = 0;i < (1<<n);i ++){
int t = i;
while(t){
if(t&1) need[i] ++;
t >>= 1;
}
}
//预处理合适的状态
for(int i = 0;i < (1<<n);i ++) if(((i<<1)&i) == 0) vis[i] = 1;
//预处理第一行
for(int i = 0;i < (1<<n);i ++) if(vis[i] && need[i] <= k) dp[1][i][need[i]] = 1;
for(int i = 2;i <= n;i ++){
for(int j = 0;j < (1<<n);j ++){
if(vis[j]){
for(int h = 0;h < (1<<n);h ++){
if(vis[h] && (h&j) == 0 && ((h<<1)&j) == 0 && ((h>>1)&j) == 0){
for(int len = k;len >= need[j];len --)
dp[i][j][len] += dp[i-1][h][len-need[j]];
}
}
}
}
}
ll ans = 0;
for(int i = 0;i < (1<<n);i ++) ans += dp[n][i][k];
cout << ans;
return 0;
}